在IB與相關文件做連接時,我們經常會用到兩個關鍵字:IBOutlet和IBAction。經常用xib或storyboard的童鞋應該用這兩上關鍵字非常熟悉了。不過UIKit還提供了另一個偽關鍵字IBOutletCollection,我們使用這個關鍵字,可以將界面上一組相同的控件連接到同一個數組中。
我們先來看看這個偽關鍵字的定義,可以從UIKit.framework的頭文件UINibDeclarations.h找到如下定義:
#ifndef IBOutletCollection #define IBOutletCollection(ClassName) #endif
另外,在Clang源碼中,有更安全的定義方式,如下所示:
#define IBOutletCollection(ClassName) __attribute__((iboutletcollection(ClassName)))
從上面的定義可以看到,與IBOutlet不同的是,IBOutletCollection帶有一個參數,該參數是一個類名。
通常情況下,我們使用一個IBOutletCollection屬性時,屬性必須是strong的,且類型是NSArray,如下所示:
@property (strong, nonatomic) IBOutletCollection(UIScrollView) NSArray *scrollViews;
假定我們的xib文件中有三個橫向的scrollView,我們便可以將這三個scrollView都連接至scrollViews屬性,然後在我們的代碼中便可以做一些統一處理,如下所示:
- (void)setupScrollViewImages { for (UIScrollView *scrollView in self.scrollViews) { [self.imagesData enumerateObjectsUsingBlock:^(NSString *imageName, NSUInteger idx, BOOL *stop) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(scrollView.frame) * idx, 0, CGRectGetWidth(scrollView.frame), CGRectGetHeight(scrollView.frame))]; imageView.contentMode = UIViewContentModeScaleAspectFill; imageView.image = [UIImage imageNamed:imageName]; [scrollView addSubview:imageView]; }]; } }
這段代碼會影響到三個scrollView。這樣做的好處是我們不需要手動通過addObject:方法將scrollView添加到scrollViews中。
不過在使用IBOutletCollection時,需要注意兩點:
IBOutletCollection集合中對象的順序是不確定的。我們通過調試方法可以看到集合中對象的順序跟我們連接的順序是一樣的。但是這個順序可能會因為不同版本的Xcode而有所不同。所以我們不應該試圖在代碼中去假定這種順序。
不管IBOutletCollection(ClassName)中的控件是什麼,屬性的類型始終是NSArray。實際上,我們可以聲明是任何類型,如NSSet,NSMutableArray,甚至可以是UIColor,但不管我們在此設置的是什麼類,IBOutletCollection屬性總是指向一個NSArray數組。
關於第二點,我們以上面的scrollViews為例,作如下修改:
@property (strong, nonatomic) IBOutletCollection(UIScrollView) NSSet *scrollViews;
實際上我們在控制台打印這個scrollViews時,結果如下所示:
(lldb) po self.scrollViews(,,)
可以看到,它指向的是一個NSArray數組。
另外,IBOutletCollection實際上在iOS 4版本中就有了。不過,現在的Objective-C已經支持object literals了,所以定義數組可以直接用@[],方便了許多。而且object literals方式可以添加不在xib中的用代碼定義的視圖,所以顯得更加靈活。當然,兩種方式選擇哪一種,就看我們自己的實際需要和喜好了。
參考
IBAction / IBOutlet / IBOutletCollection
IBOutletCollection.m