1、@property與@synthesize配對使用。
- @property預編譯指令的作用是自動聲明屬性的setter和getter方法。
- @synthesize 建立了該屬性的通路代碼
- 功能:讓編譯好器自動編寫一個與資料成員同名的方法聲明來省去讀寫方法的聲明。
2、強引用(__strong)和 弱引用(__weak)
- 在Objective-C的ARC模式中,
id obj1 = [[NSObject alloc] init];
- 這裡雖然沒有顯示的聲明為__strong,但是Objective-C預設聲明的一個對象就為__strong,即:
id obj1 = [[NSObject alloc] init];
- 和
id __strong obj1 = [[NSObject alloc] init];
- 是等價的。
- 在強引用中,有時會出現循環引用的情況,這時就需要弱引用來幫忙(__weak)。
- 強引用持有對象,弱引用不持有對象。
- 強引用可以釋放對象,但弱引用不可以,因為弱引用不持有對象,當弱引用指向一個強引用所持有的對象時,當強引用将對象釋放掉後,弱引用會自動的被指派為nil,即弱引用會自動的指向nil。
- 下面用代碼來說明:
//
// main.m
// ARC中的強引用和弱引用
//
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
id __weak obj0 = nil;
if (YES) {
id obj1 = [[NSObject alloc] init];
obj0 = obj1;
NSLog(@"obj0: %@", obj0);
}
NSLog(@"obj0: %@", obj0);
}
return 0;
}
/*
* 輸出結果
* obj0: <NSObject: 0x1003066c0>
* obj0: (null)
*
* 因為obj1生成的預設的為強引用(__strong),在超出if的作用域之後,obj1所持有的對象被釋放,
* obj0為弱引用,是以obj0不持有對象,在obj1對象釋放後,obj0自動的被指派為nil
* 弱引用的特性是,不持有對象,即便是寫成id __weak obj1 = [[NSObject alloc] init];
* 此代碼系統會給與警告,因為這裡obj1被聲明成弱引用,那麼在指派之後,alloc出來的對象會被立即釋放。
*/
3、點表達式,可以用來通路對象,類似C語言的結構體通路。
- 點表達式出現在等号的左邊,該變量名稱的setter方法将被調用;點表達式出現在等号的右邊,該變量名稱的getter方法将被調用。
4、什麼是Category
- Category模式用于向已經存在的類添加方法進而達到擴充已有類的目的,在很多情形下Category也是比建立子類更優的選擇。
- 新添加的方法同樣也會被被擴充的類的所有子類自動繼承。
- 當知道已有類中某個方法有BUG,但是這個類是以庫的形式存在的,我們無法直接修改源代碼的時候,Category也可以用于替代這個已有類中某個方法的實體,進而達到修複BUG的目的。
- 然而卻沒有什麼便捷的途徑可以去調用已有類中原有的那個被替換掉方法實體了。
-
4.1 Category的用途:
- 在不建立繼承類的情況下實作對已有類的擴充。
- 簡化類的開發工作(當一個類需要多個程式員協同開發的時候,Category可以将同一個類根據用途分别放在不同的源檔案中,進而便于程式員獨立開發相應的方法集合)。
- 将常用的相關的方法分組。
- 在沒有源代碼的情況下可以用來修複BUG。
-
4.2 Category的用法
- 在Obj-C中,聲明某一個已有類的Category擴充的方法如下:
@interface ClassName (CategoryName) -methodName1 -methodName2 @end
- 上面的聲明通常是在.h檔案中,然後我們在.m檔案中實作這些方法:
@implementation ClassName (CategoryName) -methodName1 -methodName2 @end
- 我們建立一個iOS Single View Applciation名為CategoryExample。然後為建立一個NSString類的category擴充。File->New->File然後選擇 Cocoa Touch Objective-C category.命名為ReverseNSString.系統會自動生成一個固定格式ClassName+CategoryName的.h和.m檔案。
- 聲明Category
- 打開NSString+ReverseNSString.h檔案,在裡面添加如下代碼:
#import <Foundation/Foundation.h> @interface NSString (ReverseNSString) + (NSString*) reverseString:(NSString*)strSrc; @end
- 實作Category
- NSString+ReverseNSString.m檔案中實作reverseString方法:
#import"NSString+ReverseNSString.h" @implementationNSString (ReverseNSString) + (NSString*)reverseString:(NSString*)strSrc { NSMutableString *reversedString = [[NSMutableString alloc]init]; NSInteger charIndex = [strSrc length]; while (charIndex > 0) { charIndex--; NSRange subStrRange =NSMakeRange(charIndex, 1); [reversedString appendString:[strSrcsubstringWithRange:subStrRange]]; } return reversedString; } @end
- 剩下的工作就是驗證我們的Category了,在view中添加一個按鈕ReverseString,并設定相應的action方法為reverseString.在view上再添加一個label,命名為myString,預設值是”HelloCategory Design Pattern!”。點選按鈕反轉這個字元串。主要代碼如下:
- (IBAction)reverseString:(id)sender { NSString *test = [NSStringreverseString:_myString.text]; _myString.text = test; }
-
4.3 代碼組織
- Category用于大型類有效分解。通常一個大型類的方法可以根據某種邏輯或是相關性分解為不同的組,一個類的代碼量越大,将這個類分解到不同的檔案中就顯得越有用,每個檔案中分别是這個類的某些相關方法的集合。
- 當有多個開發者共同完成一個項目時,每個人所承擔的是單獨的cagegory的開發和維護。這樣就版本控制就更加簡單了,因為開發人員之間的工作沖突更少了。
-
4.4 Category VS 添加子類
- 并沒有什麼界限分明的判定标準來作為何時用Category何時用添加子類的方法的指導。但是有以下幾個指導性的建議:
- 如果需要添加一個新的變量,則需添加子類。
- 如果隻是添加一個新的方法,用Category是比較好的選擇。
- 并沒有什麼界限分明的判定标準來作為何時用Category何時用添加子類的方法的指導。但是有以下幾個指導性的建議:
5、Class Extension(類擴充)
- class extensions用于解決兩個問題:
- 允許一個對象可以擁有一個私有的interface,且可由編譯器驗證。
- 支援一個公有隻讀,私有可寫的屬性。
- 若要定義私有函數,通常是在實作檔案中聲明一個"Private" category:
@interface MyClass (Private)
- (id)awesomePrivateMethod;
@end
- 然而, 類的私用方法通常是希望實作在類的@implementation塊中的,而不是像上面的Category的方法那樣實作在獨立的@implementation區塊中。事實上,Category僅僅是彌補了Objective-C缺少public/private限定的不足。
- 真正的問題是Objective-C編譯器會認為在Category中聲明的方法将會在别處實作,是以編譯器并不會嘗試确認它們是不是真得都被實作了。也就是說,開發者聲明的方法有可能并未實作,而且編譯器也不會有什麼警告。編譯會以為它們将在别的地方或獨立的檔案中實作。
- 使用class exteionsion,在其中聲明的方法和屬性的實作将放在class的@implementation區塊中。否則,編譯器就會報錯。
// someClass.m
@interface someClass ()
-(void)extend;
@end
@implementation someClass
// 所有聲明在頭檔案或父類中方法的實作
// 或者一些私有函數
-(void)extend {
// implement private method here;
}
@end
- 公有可讀、私有可寫的屬性(Publicly-Readable, Privately-Writeable Properties)
- 實作一個不可變(immutable)的資料結構通常有一個好處是外部代碼不能用setter修改對象的狀态。然而,可能又希望它在内部又是一個可寫的屬性。Class extensions可以做到這一點:在公共接口(類的聲明中)中,開發者可以聲明一個屬性是隻讀的,随後在類擴充中聲明為可寫。這樣,對外部代碼而言,該屬性将是隻讀的,而内部代碼卻可以使用它setter方法。
@interface MyClass : NSObject
@property (retain, readonly) float value;
@end
// 私有的extension, 隐藏在主實作檔案中.
@interface MyClass ()
@property (retain, readwrite) float value;
@end
6、判斷對象類型
- 對象在運作時擷取其類型的能力稱為内省。内省可以有多種方法實作。
- **-(BOOL) isKindOfClass: classObj **判斷是否是這個類或者這個類的子類的執行個體
- **-(BOOL) isMemberOfClass: classObj **判斷是否是這個類的執行個體
7、尖括号的含義
- 聲明語句後面的尖括号内的内容辨別遵守的協定的名稱,如果協定有多個,則在尖括号内部以逗号分隔列出來。
8、self和self class指針的差別
- self是執行個體的指針,[self class]是類的指針,靜态方法得用類的指針來調用
9、@optional和@required
- 如果指定的關鍵字@required,則該方法是必須實作的,如果指定了@optional,該方法不是必須實作。
作者: CH520