IOS6學習筆記(二)

四.使用關聯引用爲分類添加數據安全

  雖然不能在分類中建立實例變量,可是能夠建立關聯引用(associative reference)。經過關聯引用,你能夠向任何對象中添加鍵-值(key-value)數據。性能

  假若有一個Person類,這個person類可能會被用在其餘程序中,有些電子郵件地址(emailAddress)這個字段是有意義的,有些時候這個字段是沒有用的。一個比較好的解決方案就是使用分類爲Person類添加一個名爲emailAddress的屬性,這樣能夠避免不須要emailAddress時的開銷。或許Person類並非你寫的,改類的維護者也不會爲你添加這個屬性。這種狀況下,要怎麼解決問題看?首先看一下Person類的定義:atom

  @interface Person:NSObjectspa

  @property (nonatomic, readwrite, copy) NSString *name;線程

  @end;對象

  @implementation Person繼承

  @end內存

  如今使用關聯引用在分類中添加一個emailAddress屬性:ci

  #import<objc/runtime.h>get

  @interface Person(EmailAddress)

  @property (nonatomic, readwrite, copy) NSString *emailAddress;

  @end

  @implementation Person (EmailAddress)

  static char emailAddressKey;

  - (NSString *)emailAddress{

    return objc_getAssociatedObject(self, &emailAddressKey);

  }

  - (void)setEmailAddress:(NSString *)emailAddress{

    objc_setAssociatedObject(self, &emailAddressKey,emailAddress,OBJC_ASSOCIATION_COPY);

  }

  @end

  能夠看出,關聯引用是基於鍵(key)的內存地址的,而不是鍵的值。在emailAddressKey中儲存的內容並不重要,可是它須要一個惟一地址,因此一般使用一個未賦值的static char 做爲鍵。

  若是要在警告面板中關聯一個對象,使用關聯引用是一個很是好的方式。例:

#import "ViewController.h"

#import <objc/runtime.h>

 

@implementation ViewController

 

static const char kRepresentedObject;

 

- (IBAction)doSomething:(id)sender {

  UIAlertView *alert = [[UIAlertViewalloc]

                        initWithTitle:@"Alert" message:nil

                        delegate:self

                        cancelButtonTitle:@"OK"

                        otherButtonTitles:nil];

  objc_setAssociatedObject(alert, &kRepresentedObject

                           sender,

                           OBJC_ASSOCIATION_RETAIN_NONATOMIC);

  [alert show];

  

}

 

- (void)alertView:(UIAlertView *)alertView 

clickedButtonAtIndex:(NSInteger)buttonIndex {

  UIButton *sender = objc_getAssociatedObject(alertView, 

                                              &kRepresentedObject);

  self.buttonLabel.text = [[sender titleLabel] text];

}

@end

 

五.類擴展(class extension)

  類擴展的聲明方式跟分類很像,只不過括號內的名字是空的:

  @interface MyObject()

  - (void)doSomething;

  @end

  類擴展是在.m文件中聲明私有方法的一個很棒的方式。不一樣於分類,在類擴展中聲明的方法與在類中聲明的方法是徹底一致的,這些方法必須所有實現(分類的方法沒必要全都實現),且在編譯時被添加到類中,而分類是在運行時添加。在類擴展中也能夠聲明合成屬性。

六.協議

  協議跟類同樣能夠繼承。協議應該老是繼承<NSObject>,就像類老是繼承NSObject同樣。委託協議(delegate protocol)的第一個參數老是委託對象。正是所以,一個委託才能管理多個委託對象。好比,一個控制器就能夠做爲多個UIAlertView實例的委託來使用。注意在委託對象以外是否還有其餘參數,這對命名約定有必定影響。若是沒有參數,類名應該最後出現(numberOfSectionsInTableView:);若是有其餘參數,類名要首先出現,做爲它自身的參數(tableView:numberOfRowsInSection:)。

  建立協議以後,一般還須要一個屬性以便於操做它,一般使用id<Protocol>的方式來聲明:

  @property(nonatomic, readwrite, weak) id<MyDelegate> delegate;

  這表示「與MyDelegate協議相容的任何對象」。同事使用類和協議聲明一個屬性也是能夠的,並且可使用多個協議:

  @property(nonatomic, readwrite, weak) MyClass *<MyDelegate,UITableViewDelegate> delegate;

  這個屬性聲明是說delegate必須是MyClass或其子類的對象,並且必須同時與<MyDelegate>和<UITableViewDelegate>協議相容。

 

六.單例

  建議使用Grand Center Dispatch(CCD):

  + (MYSingleton *)sharedSingleton{

    static dispatch_once_t pred;

    static MYSingleton *instance = nil;

    dispatch_once(&pred, ^{instance = [[self alloc] init];});

    return instance;

  }

  這樣編寫方便、快速,並且線程安全。其餘方法要在+sharedSingleton中添加一個@synchronize以達到線程安全的目的,可是這種作法在每次調用+sharedSingleton時都會致使性能顯著降低。另外,還可使用+initialize,但使用GCD的方法最簡單。

  強制執行單例:

  + (MYSingleton *)sharedSingleton{

    static dispatch_once_t pred;

    static MYSingleton *instance = nil;

    dispatch_once(&pred, ^{instance = [[self alloc] init];});

    return instance;

  }

  - (id)init{

    //禁用調用-init或new

    NSAssert(NO, @"Cannot create instance of Singleton");

    //在這裏,你能夠返回nil或[self initSingleton],由你來決定是返回nil仍是返回[self...]

    return nil;

   }

  //真正的(私有)init方法

  - (id)initSingleton{

    self = [super init];

    if(self){

      //初始化代碼

    }

    return self;

  }

相關文章
相關標籤/搜索