refer to http://pernghh.pixnet.net/blog/post/33563421-objective-c-%E5%8F%8A-iphone-sdk-%E5%85%A5%E9%96%80
Objective-C裏的實體變數都會定義它的存取範圍。一般來說外部的物件並不會(該)直接去存取這些變數,而是透過該物件提供的方法來存取,這些方法可以透過在物件的宣告中定義專屬於物件的特性(Property)來讓系統幫我們產生而不必由我們親自動手來撰寫。
雖然在物件中有些變數是允許給外部存取的,但是習慣上我們通常不會直接去存取這些變數,而是透過特性來存取。因為利用特性存取這些變數能夠提供我們許多額外
的好處,包括了簡化物件的記憶體操作、在多執行緒下的變數存取的管理等等。因此,在實務上,即使某個物件將它的某個變數開放出來讓我們使用,我們仍應該先
檢查該變數是否有對應的特性可以使用,如果沒有,而又必須對該變數做操作時才會對變數直接做操作。
特性為類別提供了一個給外面元件存取它內部變數的一個方法。當類別宣告特性之後,系統會自動為特性製作相關的存取方法。這些方法稱為特性的存取方法(accessor method)。存取方法分成下面兩類:
setter
|
提供設定特性的功能
|
getter
|
提供了讀取特性的功能
|
setter在一般的程式中就是類似 setVariable(),而getter則是 類似getVariable() 的方法。不過這些setter和getter方法並不需要我們自己實作,只要對特性進行適當地設定,系統就會自動幫我們合成這些實作的內容。
特性可以經由設定使它適合在多執行緒的環境使用,因此妥善的特性規劃可以簡化程式的設計,下面是幾種特性的宣告方式
基本語法
@property (attributes) Type propertyName;
example
@interface MyClass : NSObject |
@property float value; |
@end |
其中@property float value = 下面兩行的語法
- (float)value; |
- (void)setValue:(float)newValue; |
配合屬性的例子
@property (nonatomic,retain) UIView * testView;
@property (atomic) int fileCount;
@property (nonatomic,assign) UIMyDelegete * delegate;
@property (nonatomic,assign) UIView * parentView;
refer to http://sevensavants.blogspot.com/2012/03/objective-cdeclared-properties.html
@interface MyClass : NSObject {NSNumber *_myNumber; }
// Accessor - Getter
- (NSNumber *)myNumber;
// Accessor - Setter
- (void)setMyNumber:(NSNumber *)newNumber;
@end
@implementation MyClass
// Accessor - Getter
- (NSNumber *)myNumber {
return _myNumber;
}
// Accessor - Setter
- (void)setMyNumber:(NSNumber *)newNumber {
if (newNumber != _myNumber) {
[_myNumber release];
_myNumber = [newNumber retain];
}
}
@end
用Declared Properties之後簡化很多
@interface MyClass : NSObject
@property(retain) myNumber;
@end
@implementation MyClass
@synthesize myNumber
@end
另外properties有很多屬性attributes
Property Declaration Attributes (refer to IOS web)
Accessor Method Names
The default names for the getter and setter methods associated with a property are propertyName and
setPropertyName: respectively—for example, given a property “foo”, the accessors would be foo and setFoo:. The following attributes allow you to specify custom names instead. They are both optional and can appear with any other attribute (except for readonly in the case of setter=).getter=getterName- Specifies the name of the get accessor for the property. The getter must return a type matching the property’s type and take no parameters.
setter=setterName- Specifies the name of the set accessor for the property. The setter method must take a single parameter of a type matching the property’s type and must return
void.If you specify that a property isreadonlyand also specify a setter withsetter=, you get a compiler warning.
Typically you should specify accessor method names that are key-value coding compliant (see Key-Value Coding Programming Guide)—a common reason for using the
getter decorator is to adhere to the isPropertyName convention for Boolean values.Writability
These attributes specify whether or not a property has an associated set accessor. They are mutually exclusive.
readwrite- Indicates that the property should be treated as read/write. This attribute is the default.Both a getter and setter method are required in the
@implementationblock. If you use the@synthesizedirective in the implementation block, the getter and setter methods are synthesized. readonly- Indicates that the property is read-only.If you specify
readonly, only a getter method is required in the@implementationblock. If you use the@synthesizedirective in the implementation block, only the getter method is synthesized. Moreover, if you attempt to assign a value using the dot syntax, you get a compiler error.
Setter Semantics
These attributes specify the semantics of a set accessor. They are mutually exclusive.
strong- Specifies that there is a strong (owning) relationship to the destination object.
weak- Specifies that there is a weak (non-owning) relationship to the destination object.If the destination object is deallocated, the property value is automatically set to
nil.(Weak properties are not supported on OS X v10.6 and iOS 4; useassigninstead.) copy- Specifies that a copy of the object should be used for assignment.
assign- Specifies that the setter uses simple assignment. This attribute is the default.You use this attribute for scalar types such as
NSIntegerandCGRect. retain-
In OS X v10.6 and later, you can use the
__attribute__keyword to specify that a Core Foundation property should be treated like an Objective-C object for memory management:@property(retain) __attribute__((NSObject)) CFDictionaryRef myDictionary;
Atomicity
You can use this attribute to specify that accessor methods are not atomic. (There is no keyword to denote atomic.)
nonatomic- Specifies that accessors are nonatomic. By default, accessors are atomic.
Properties are atomic by default so that synthesized accessors provide robust access to properties in a multithreaded environment—that is, the value returned from the getter or set via the setter is always fully retrieved or set regardless of what other threads are executing concurrently.
If you specify
strong, copy, or retain and do not specify nonatomic, then in a reference-counted environment, a synthesized get accessor for an object property uses a lock and retains and autoreleases the returned value—the implementation will be similar to the following:[_internal lock]; // lock using an object-level lock |
id result = [[value retain] autorelease]; |
[_internal unlock]; |
return result; |
If you specify
nonatomic, a synthesized accessor for an object property simply returns the value directly.Markup and Deprecation
Properties support the full range of C-style decorators. Properties can be deprecated and support
__attribute__ style markup:@property CGFloat x |
AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; |
@property CGFloat y __attribute__((...)); |
If you want to specify that a property is an outlet (see outlet in iOS, and outlet in OS X), you use the
IBOutlet identifier:@property (nonatomic, weak) IBOutlet NSButton *myButton; |
IBOutlet is not, though, a formal part of the list of attributes. For more about declaring outlet properties, see “Nib Files”.另外一個例子
@property (nonatomic, copy) NSString *name;
因為copy這個屬性,得到的 synthesized method that behaves like this:-(void) setName: (NSString *) theName
{
if (theName != name) {
[name release]
name = [theName copy];
}
}
Use of nonatomic here tells the system not to protect the property accessors with a
mutex (mutually exclusive) lock
If nonatomic is not specified or atomic is specified instead (which is the default), then
your instance variable will be protected with a mutex lock.
應該說明的是,由於 object 的性質各有不同,如果有需要用到copy指令,你應該為你的object class 加入 -(id)copyWithZone:(NSZone*)zone 函數。有興趣知道更多的話,可以到這裡參考。
參考:http://edwardinaction.blogspot.tw/2012/03/automatic-reference-counting-in.html
手動管理 Reference count
在我們手動管理記憶體 reference count ,程式上會需要 alloc 和 init,這時物件會回傳 retain count,因此在結束後必須要 release 它。
如果不知道呼叫者何時不需要使用,要加上 autorelease。
基本上,如果沒有特別需求,就使用strong如果一時無法理解也沒關係,如果沒有特別原因,可以先用【基本資料類型不設參數, 類別資料類型設 (nonatomic, strong)】設就可以了,其他的等到學習 delegate,多線程,自訂 setter 等需要參數時,文件中有特別註明是,再來理解就可以了。
@property (nonatomic, strong) NSString *testString;
mutex (mutually exclusive) lock
If nonatomic is not specified or atomic is specified instead (which is the default), then
your instance variable will be protected with a mutex lock.
MyObject *originalObject = [[MyObject alloc] init]; MyObject *duplicatedObject = [originalObject copy];以上兩行指令已經分配了兩塊 memory。對其中一個 object 所做的改變,不會影響到另外一個,且他們各自的 retain count 為1。
應該說明的是,由於 object 的性質各有不同,如果有需要用到copy指令,你應該為你的object class 加入 -(id)copyWithZone:(NSZone*)zone 函數。有興趣知道更多的話,可以到這裡參考。
參考:http://edwardinaction.blogspot.tw/2012/03/automatic-reference-counting-in.html
手動管理 Reference count
在我們手動管理記憶體 reference count ,程式上會需要 alloc 和 init,這時物件會回傳 retain count,因此在結束後必須要 release 它。
如果不知道呼叫者何時不需要使用,要加上 autorelease。
Automatic Reference Counting
有個概念很重要,這不是我們在別的程式語言像是 Java 所提到 Garbage Collection,因為 Garbage Collection 是在 Run-time 期間處理的。這些 Reference Counting 依舊存在,只是在編譯階段幫我們處理掉,讓我們不用再煩惱釋放狀況了。使用了 Automatic Reference Counting 之後,我們則需要寫成這樣。
有個概念很重要,這不是我們在別的程式語言像是 Java 所提到 Garbage Collection,因為 Garbage Collection 是在 Run-time 期間處理的。這些 Reference Counting 依舊存在,只是在編譯階段幫我們處理掉,讓我們不用再煩惱釋放狀況了。使用了 Automatic Reference Counting 之後,我們則需要寫成這樣。
ARC 的使用方法
- Alloc, init objects - 當在宣告一個物件時候使用 alloc 和 init,但是千萬不要加上任何的 retain, release 或者 autorelease。當然也不要用任何 Selector 去呼叫 @selector(retain) 或者 @selector(release)。
- Dealloc - 就不要在寫 dealloc 了。ARC 會幫我們做到,除非我們想要做些特別處理,但是使用了 dealloc 就不要再呼叫 [super dealloc] 了,這部分也是會幫忙做到。
- 宣告 Properties - 在還沒有使用 ARC 以前,我們宣告要用到 assign, retain 或者 copy 這些處理記憶體的寫法,這些在 ARC 裡面不會使用了。取而代之的是 weak 和 strong 來告訴編譯器我們在程式上是如何使用的。
- 使用 Variables - 要使用 strong, weak, unsafe_unretained, autoreleasing。
Strong 與 Weak
- Strong 的參考上是參考到一個物件一直到當該物件被 deallocted,也就是會幫我們建立出彼此的關聯性,建立彼此的擁有權生命週期。
- Weak 的參考上是一直對應到該物件,就算這個物件被 dealloc 了還是存在。所以它不會建立擁有權。
- _strong 是預設值,所以不打出來就是這樣的方式,建立了物件就會幫忙處理所有的 retained 和 released,自己內部這個物件使用。
- _weak 代表這個物件可以隨時不見都沒有關係,如果對應到某個物件就算被 dealloc 它就會變成 nil 。
- unsafe_unretained 這是跟 weak 一樣,但是當物件被 dealloc 不會將指標變成 nil。只是會變成指到無效的物件。
- _autoreleasing 這會指引到該物件並且建立 autorelease 關係。
基本上,如果沒有特別需求,就使用strong如果一時無法理解也沒關係,如果沒有特別原因,可以先用【基本資料類型不設參數, 類別資料類型設 (nonatomic, strong)】設就可以了,其他的等到學習 delegate,多線程,自訂 setter 等需要參數時,文件中有特別註明是,再來理解就可以了。
@property (nonatomic, strong) NSString *testString;
在 Project 裡面開啟 ARC
要打開 ARC 只要在 Xcode project’s build setting 找到 reference counting 將它設定為 YES,那麼就會幫我們在編譯階段加上 -fobjc-arc 編譯 flag 來處理。
將既有的 Projects 轉換成為 ARC
打開不是 non-ARC 的 Project 在 Edit -> Refactor -> Convert to Objects-C ARC。會出現一個勾選確認的表單,再點選後程式上會將非 ARC 程式碼轉成 ARC 。如果這過程有些狀況在視情況處理。好了之後可以到 build setting 裡面找 reference counting 是否改為 YES 了。
引用了 Code 不是 ARC 建立出來的
我 們還是可以將 ARC 與 non-ARC 的程式碼並存使用,在 Xcode Project 找到 Target 裡面的 Build Phases tab ,展開 Compile Sources 區域將這些程式碼檔案拍開到 ARC 之外,在後面的 key 地方一一加上 -fno-objc-arc ,目前我還找不到可以一次改多個檔案,所以只好一個一個加。因此當加了這些編譯註記,那麼就會被排外。
最後
如 果新的 Objective-C 學習者,來使用 ARC 會很適合,這可以不用在初期寫程式就傷腦筋 reference count 的管理,而如果像是已經寫 Objective-C 一陣子了如果習慣這樣用法不使用也沒關係,目前為止還是有很多的 libraries 或是 Open Source Projects 還沒轉成 ARC。當然以效能上來說,有些參考數據已經顯示 ARC 可以讓 Project 跑起來更為快速,在 release 或是 autorelease 會用的非常恰當。ARC 的任務是選擇最優化、自動化的方式來幫程式碼加上這些管理。當然最根本程式上不論使用了 ARC 或者 non-ARC,寫 Code 的嚴謹還是最重要的。
要打開 ARC 只要在 Xcode project’s build setting 找到 reference counting 將它設定為 YES,那麼就會幫我們在編譯階段加上 -fobjc-arc 編譯 flag 來處理。
將既有的 Projects 轉換成為 ARC
打開不是 non-ARC 的 Project 在 Edit -> Refactor -> Convert to Objects-C ARC。會出現一個勾選確認的表單,再點選後程式上會將非 ARC 程式碼轉成 ARC 。如果這過程有些狀況在視情況處理。好了之後可以到 build setting 裡面找 reference counting 是否改為 YES 了。
引用了 Code 不是 ARC 建立出來的
我 們還是可以將 ARC 與 non-ARC 的程式碼並存使用,在 Xcode Project 找到 Target 裡面的 Build Phases tab ,展開 Compile Sources 區域將這些程式碼檔案拍開到 ARC 之外,在後面的 key 地方一一加上 -fno-objc-arc ,目前我還找不到可以一次改多個檔案,所以只好一個一個加。因此當加了這些編譯註記,那麼就會被排外。
最後
如 果新的 Objective-C 學習者,來使用 ARC 會很適合,這可以不用在初期寫程式就傷腦筋 reference count 的管理,而如果像是已經寫 Objective-C 一陣子了如果習慣這樣用法不使用也沒關係,目前為止還是有很多的 libraries 或是 Open Source Projects 還沒轉成 ARC。當然以效能上來說,有些參考數據已經顯示 ARC 可以讓 Project 跑起來更為快速,在 release 或是 autorelease 會用的非常恰當。ARC 的任務是選擇最優化、自動化的方式來幫程式碼加上這些管理。當然最根本程式上不論使用了 ARC 或者 non-ARC,寫 Code 的嚴謹還是最重要的。



沒有留言:
張貼留言