iOS Protocol、Category中聲明屬性方法詳情,ioscategory
之前一直有一個誤區,認為協議和分類中不能用@property 形式聲明屬性,現在做一下總結:
iOS中協議中和分類中是可以用@property形式聲明屬性的,只不過在協議、分類中聲明的屬性,只有對應的setter/getter方法,並沒有產生對應的成員變數。因為協議中只可以聲明方法,分類中只能聲明方法和對應的實現。
那麼如何在協議中用@property聲明屬性,然後在實現協議的類中可以用成員變數直接存取屬性的值?
Protocol:
@protocol MyProtocol @property (nonatomic,strong) NSString *myImage;@end
實作類別:
@interface ViewController : UIViewController@end@implementation ViewController@synthesize myImage = _myImage;- (void)viewDidLoad { [super viewDidLoad]; self.myImage = @"my string"; NSLog(@"%@,%@",_myImage,self.myImage);@end
上面方法中主要用到了@synthesize 上面聲明部分的 @synthesize myImage = _myImage; 意思是說,myImage 屬性為 _myImage 成員變數合成訪問器方法。 也就是說,myImage屬性產生存取方法是setMyImage,這個setMyImage方法就是_myImage變數的存取方法,它操作的就是_myImage這個變數。通過這個看似是賦值的這樣一個操作,我們可以在@synthesize 中定義與變數名不相同的getter和setter的命名,籍此來保護變數不會被不恰當的訪問。比如完全可以寫成:
@interface ViewController : UIViewController@end@implementation ViewController@synthesize myImage = _helloWorld; //set方法的值儲存在_helloWorld中- (void)viewDidLoad { [super viewDidLoad]; self.myImage = @"my string"; NSLog(@"%@,%@", _helloWorld,self.myImage); //self.myImage 取的就是成員變數_helloWorld的值;@end
根據上面的結論那麼Category中能否一樣使用 @synthesize來儲存成員變數的值呢?
只可惜Category中的implementation中不支援用@synthesize 來合成屬性,正確的做法可以這樣:
Category:
@interface NSObject (Extension)@property (nonatomic,strong) NSString *myTitle;@end#import @implementation NSObject (Extension)- (NSString *)myTitle { return objc_getAssociatedObject(self, @selector(myTitle)); }- (void)setMyTitle:(NSString *)myTitle { objc_setAssociatedObject(self, @selector(myTitle), myTitle,OBJC_ASSOCIATION_RETAIN);}
這樣在實作類別中同樣可以使用.xx擷取存取的值:
@interface ViewController : UIViewController@end#import "NSObject+Extension.h"@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; NSObject *myObj = [[NSObject alloc] init]; myObj.myTitle = @"my title"; NSLog(@"%@",myObj.myTitle);@end
補充:@dynamic 和 @synthesize的區別:
在@implementation 中通過@dynamic xxx 告訴編譯器、xxx屬性的setter、getter方法由開發人員自己來產生
@ synthesize xxx = _xxx; 告訴編譯器、xxx屬性的setter、getter方法由編譯器來產生、同時用_xxx 來合成 成員變數