介紹了Objective-C 的一些關鍵知識點,包括點訪問方法,strong 和weak 的比較,nil,實例化,動態綁定技術(程序在執行時纔會知道要執行的代碼有沒有),自省(選擇器的使用),基礎的框架如NSObject,NSString 等等。
這些是開發的基礎,整理了一遍有利於程序的開發和調整。像類方法只能使用類來調用,實例方法只能使用實例,這點以前還沒有明白。對於在實例中怎麼不能調用類方法的問題還疑惑了一陣子。
1 、點符號方法訪問屬性變量
在property 引進後開始使用這個方法,蘋果官方解釋爲這樣做是出於代碼美觀考慮。蘋果的產品將美觀放在第一位,這產品包括了obj-c 的代碼。
使用點符號法self.propery 訪問@property 比普通的[self property] 方法更直觀。在C 結構體中,也是使用點符號方法訪問屬性。這兩個方法看上去很相似,但它們有兩點大不同:
其一,我們不能發送消息給C 結構體,因爲C 結構體根本沒有可執行的方法。
其二,C 結構體絕不分配在heap 中,因此不能通過指針來訪問到它。(注,它分配在stack 中。內存管理中分爲heap 和stack )
2 、 strong 和 weak
在定義@property 時,會有選項如strong 、weak 等。
strong 表示保存這個對象在heap 中直到不再有任何指針指向它。(注,我理解爲所有指向它的指針不先設置爲nil ,它就不會從heap 中清理。)
weak 表示保存這個對象在heap 中,只要其他人strongly 指向了它。如果它從heap 中清理了,會將所有指向它的指針調整爲指向nil 。這個功能從iOS5 開始使用。(注,我理解爲如果它從heap 中清理後,所有指向它的指針都會自動調整爲nil 。)
但是這種清理heap 的機制不是垃圾回收機制,在iOS 上沒有這種內存自動回收機制。它採用的一種更好的機制,稱之爲引用計算(reference counting )。這種機制可以展開來講很多,但在iOS 中又有了新機制,稱爲自動應用計算(ARC) 。瞭解它可以有助於理解內存管理。
在iOS 中還有一種內存釋放方法,爲dealloc 。
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
這種方法很少會用到,因爲如果用到它,則太遲了。估計iOS 已經將應用給殺死了。
3 、 nil
這是一個對象指針的值,表示不指向任何對象。它和原始類型如int double 的“zero “很相似。
在實例變量中,作爲一個對象指針類型定義的,其初始值都是nil 。如
id obj = nil;
NSString *hello = nil;
nil 還有一個隱藏的功能,就是它可以放在if 語句中做條件判斷。
如if (obj) {run something;} 這個語句,obj 爲nil 時則不執行,不爲nil 則執行。
對於指針值爲nil 的實例變量,任何調用該對象中方法,都不會出錯,沒有任何方法會被執行。這可以理解爲向nil 發送消息時,沒得執行啊。
該操作的返回值是0 。如果int i = [obj methodWhichReturnsAnInt]; 則沒有問題,返回結果是0 ,屬於int 類型;如果CGPoint p = [obj getLocation]; 則就有問題了,返回結果還是0 ,而0 不是CGPoint 類型。CGPoint 是一個C 結構體。(注,類型不一致,會不會crash? )
4 、 BOOL 類型
在Objective-C ,也有一種布爾類型,實質上它是typedef 。
它可以用來做條件判斷
if (flag) { }
if (!flag) { }
YES 值意思爲true ,NO 值意思爲false
N0 值等於0 ,YES 值除0 之外所有的數字
5 、實例方法和類方法
這個知識點很重要,在obj-c 中使用範圍很廣。他們之間區別有下列幾點需要說明。
第一,命名方式上的差別,實例方法是以“- ”開始,類方法是以“+ ”開始。
- (BOOL)dropBomb:(Bomb *)bomb at:(CGPoint)position from:(double)altitude;// 這是實例方法在.h文件中的聲明
+ (id) alloc;// 這是類方法
+ (Ship *)motherShip;
+ (NSString *)stringWithFormat:...
第二,調用語法的差別。
實例方法只能實例去調用,語法爲[<pointer to instance> method] 。
例子:
Ship *ship = ...; // instance of a Ship
destroyed = [ship dropBomb:firecracker at:dropPoint from:300.0];
同樣,類方法只能用類去調用,語法爲[Class method] 。
例子:
Ship *ship = [Ship motherShip];//Ship 是一個類
NSString *resultString =[NSString stringWithFormat:@“%g”, result];//NSString 也是一個類型
[[ship class] doSomething];//ship 是一個實例化的對象,必須使用[ship class] 轉換成類後才能調用類方法,而直接使用ship 實例無法調用到類方法。
(注,首字符爲大寫的都是類,小寫的則是實例化的對象,這是命名規則)
第三,self/super 的區別
在類中,使用self/super 的結果都是類;
在實例中,使用self/super 的結果都是實例;
6 、實例化( Instantiation )
其一,使用其他對象創建自己的對象,如
NSString’s - (NSString *)stringByAppendingString:(NSString *)otherString;
NSString’s & NSArray’s - (id)mutableCopy;
NSArray’s - (NSString *)componentsJoinedByString:(NSString *)separator;
其二,也不是所有的使用其他對象創建而生成的對象都是新建的,有的對象會只是一個指針,而不是在heap 中再劃分內存創建對象。如,
NSArray’s - (id)lastObject;
NSArray’s - (id)objectAtIndex:(int)index;
但是,如果使用copy 關鍵字,則會創建新對象。
其三,還可以使用類方法創建對象,如
NSString’s + (id)stringWithFormat:(NSString *)format, ...
UIButton’s + (id)buttonWithType:(UIButtonType)buttonType;
NSMutableArray’s + (id)arrayWithCapacity:(int)count;
NSArray’s + (id)arrayWithObject:(id)anObject;
其四,使用Allocating 和 initializing 創建新對象
例如:
NSMutableArray *stack = [[NSMutableArray alloc] init];
CalculatorBrain *brain = [[CalculatorBrain alloc] init];
Allocating 是通過NSObject 的類方法alloc 在heap 中分配一個空間給新對象。如@synthesize 就是執行這個操作。因此所有的@sythesize 的對象都已經在heap 中分配了一個足夠大的內存空間。但這只是第一步,如果要使用該對象,還必須初始化,否則會直接crash 。
Initializing 對於多數類而言,都有很多方法,但NSObject 類只有一個初始化方法爲init 。
例如:
- (id)initWithFrame:(CGRect)aRect; // initializer for UIView
UIView *myView = [[UIView alloc] initWithFrame:thePerfectFrame];
- (id)initWithCharacters:(const unichar *)characters length:(int)length;
- (id)initWithFormat:(NSString *)format, ...;
- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding;
在開發類時,初始化方法中的返回類型建議設置成id ,這樣做是爲了繼承。如果它的子類使用它的初始化方法時,直接使用id 類型即可。
例如:
@implementation MyObject
- (id)init
{
self = [super init]; // call our super’s designated initializer
if (self) {
// initialize our subclass here
}
return self;
}
@end
7 、動態綁定
其一,所有的對象都被分配在heap 中,所以你一直可以使用指針
例如:
NSString *s = ...; // 靜態類型定義
id obj = s; // 非靜態類型定義,但完全合法,不要使用”id *” 因爲它表示一個指針的指針。
其二,在runtime 時纔會知道運行的代碼是什麼
靜態類型如第一點所說的NSString * 和id 的比較,靜態類型只不過在編譯時更有利於我們發現bug 。
如果runtime 時,沒有找到所運行的代碼,就crash 。但我們可以使用“introspection ”去判斷代碼是否可以執行。
8 、自省( introspection )
自省是對象的固有能力,即程序運行時,對象可根據請求對外透露自身基本特性。您可以給對象發送某種消息,向其詢問與它自身相關的問題,對象在Objective-C 運行時將會向您提供答案。自省是很重要的編碼工具,它可以讓程序變得更加高效健壯。
所有的繼承了NSObjec 的對象有擁有下列三個方法:“
isKindOfClass: returns whether an object is that kind of class (inheritance included)
isMemberOfClass: returns whether an object is that kind of class (no inheritance)
respondsToSelector: returns whether an object responds to a given method
方法1 的參數值爲[NSString class] ,即發送一個名爲class 的類方法給一個類而得到。例如:
if ([obj isKindOfClass:[NSString class]]) {
NSString *s = [(NSString *)obj stringByAppendingString:@”xyzzy”];
}
方法3 的參數值爲一個選擇器,如@selector(shoot) 。
如果對象中有這個方法shoot ,就響應爲true 。例如:
if ([obj respondsToSelector:@selector(shoot)]) {
[obj shoot];
} else if ([obj respondsToSelector:@selector(shootAt:)]) {
[obj shootAt:target];
}
介紹一種新類型SEL ,它是Objective-C 用於選擇器的類型。
SEL shootSelector = @selector(shoot);
SEL shootAtSelector = @selector(shootAt:);
SEL moveToSelector = @selector(moveTo:withPenColor:);
在NSObject 類中,可以通過方法performSelector: 或者 performSelector:withObject: 來執行選擇器。例如:
[obj performSelector:shootSelector];
[obj performSelector:shootAtSelector withObject:coordinate];
在NSArray 類中,可以通過makeObjectsPerformSelector: 來執行選擇器操作。例如:
[array makeObjectsPerformSelector:shootSelector]; // cool, huh?
[array makeObjectsPerformSelector:shootAtSelector withObject:target]; // target is an id
在UIButton 類中,可以通過 - (void)addTarget:(id)anObject action:(SEL)action ...; 方法來執行選擇器。例如:
[button addTarget:self action:@selector(digitPressed:) ...];
9 、基礎框架
NSObject
在IOS SDK 中,NSObject 是基礎類,實現一些方法,如自省的方法等等。
- (NSString *)description is a useful method to override (it’s %@ in NSLog()).
- (id)copy; // not all objects implement mechanism (raises exception if not)
- (id)mutableCopy; // not all objects implement mechanism (raises exception if not)
還有這些常用架構,如NSString ,NSMutableString ,NSNumber (原始類型 int, float, double, BOOL 等等的封裝成對象),NSValue ,NSData ,NSDate 。
還有一些集合類型如NSArray ,NSMutableArray ,NSDictionary ,NSMutableDictionary ,NSSet,NSMutableSet ,NSOrderedSet ,NSMutableOrderedSet 。這些分成三種類別,分別爲array,dictionary,set 。
這些類可以使用for in 方法遍歷訪問他們的成員。
還有Property List 和NSUserDefaults 兩個,也需要關注一下。