2013年5月29日 星期三

Property & Synthesize & Setter Getter

有一部分還不是很懂

先講 Setter 與 self. 關係, 舉簡單例子
假設我有一個MyObject Class, 然後在ViewController中要把它實體化
#import <UIKit/UIKit.h>
#import "MyObject.h"
@interface ViewController : UIViewController {
 MyObject *myObject;
}
@end
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
 myObject = [[MyObject alloc] init];
}
@end
這樣的方式並沒有使用到property, 也自然沒有setter, getter, 用不到也不能用 self.


再來換個方式寫
#import <UIKit/UIKit.h>
#import "MyObject.h"
@interface ViewController : UIViewController
@property (nonatomic, strong) MyObject *myObject;
@end
#import "ViewController.h"
@implementation ViewController
@synthesize myObject = _myObject;
- (void)viewDidLoad
{
    [super viewDidLoad];
 _myObject = [[MyObject alloc] init];
 //self.myObject = [[MyObject alloc] init];
}
@end

@synthesize myObject = _myObject; 這現在會自動完成, 可以省略不寫, 為了說明還是寫出來

有不少人搞不清楚 _myObject 與 self.myObject 差異在哪
那我再多寫一段自定義的Setter與Getter (大部分情況都不用override, 這只是為了說明)
- (void)setMyObject:(MyObject *)myObject {
 NSLog(@"Setter");
 _myObject = myObject;
}
- (MyObject *)myObject {
 NSLog(@"Getter");
 return _myObject;
}

這時候就可以比較看看, 把在viewDidLoad的兩個MyObject實體化方法的程式輪流註解, 可以發現
_myObject 不會 經由Setter
self.myObject 經由Setter

有沒有經過Setter的差異要從自己定義property的attribute來看, 我用ARC機制出來前的retain來說明 ,retain相當於ARC下的strong

下面說明請不要使用在ARC的project底下 會出錯的

假設說我MyObject的property這樣宣告
@property (nonatomic, retain) MyObject *myObject;

retain意義就在於我要擁有這個物件, 這會使得物件的retainCount+1
而retainCount+1這動作是在 Setter裡面完成的

系統自動產生property為retain的Setter大概如下這樣寫法, 會retain新物件, release舊物件
- (void)setMyObject:(MyObject *)myObject {
 [myObject retain];
 [_myObject release];
 _myObject = myObject;
}

如果說我物件初始化這樣寫
_myObject = [[MyObject alloc] init];
如同我之前講的, _myObject這樣的寫法不會經過Setter, 自然也不會retain, 這很不符合規範

比較好寫法應該這樣
MyObject *objectTemp = [[MyObject alloc] init];
self.myObject = objectTemp;
[objectTemp release];

可能又有人會問, 那 [objectTemp release]; 是啥
根據蘋果有一篇關於記憶體管理文章, 只要記住有 alloc retain, copy, 這三個關鍵字都會使得retainCount+1, 要出現成對的release
如果沒寫 [objectTemp release], 然後又經過Setter retain了物件一次, 這會使得retainCount=2, 會造成memory leak

再說一次, 這些都只是講觀念, 務必不要用到ARC的project上, 會出錯滴


13/7/15
網路上見到一種的Design Pattern, 叫做lazy initialization
簡單說就是在需要物件的時候才在產生實體, 需要override getter
在自定的getter中, 需要直接存取ivar, 所以不要加上 self. ,不然會造成一直重復load getter, 變成無窮迴圈

.h
@property (strong, nonatomic) NSObject *obj;

.m
- (NSObject *)obj {
if (_obj == nil) {
_obj = [[NSObject alloc] init];
}

return _obj;
}

沒有留言:

張貼留言