1. 程式人生 > >Object C語法學習筆記(二)

Object C語法學習筆記(二)

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的目的。
  • 然而卻沒有什麼便捷的途徑可以去呼叫已有類中原有的那個被替換掉方法實體了。
  • 需要注意的是,當準備有Category來替換某一個方法的時候,一定要保證實現原來方法的所有功能,否則這種替代就是沒有意義而且會引起新的BUG。
  • 和子類不同的是,Category不能用於向被擴充套件類新增例項變數。
  • Category通常作為一種組織框架程式碼的工具來使用。

  • 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是比較好的選擇。

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,該方法不是必須實現。