Object-C-代碼塊Block回顧
OC中的代碼塊是iOS4.0+ 和Mac OS X 10.6+ 引進的對C語言的擴展,用來實現匿名函數的特性。類似於其他語言腳本語言或者編程語言中的閉包或者是Lambda表達式,可能第一眼看上去很怪異,不過開發的過程中會越來越大的越到Block,還是了解多一點比較好。Block方面的內容也有很多,本文從實際使用的角度大概講一下Block的基本概念和實踐。
首先看一個蘋果官網的例子:
int (^Multiply)(int, int) = ^(int num1, int num2) {
return num1 * num2;
};
int result = Multiply(7, 4); // Result is 28.
上面的代碼定義了一個Block,類似於C#中的委托,int表示返回類型,^是關鍵標示符,(int,int)是參數類型,不過需要注意的,正常的方式是將返回類型用()包裹,這裡是將Block的名稱包裹,網上有一個類似的圖片,大家可以參考一下:
Block除了能夠定義參數列表、返回類型外,還能夠獲取被定義時的詞法范圍內的狀態(將變量作為參數傳遞之後,可以修改之後返回).Block都是一些簡短代碼片段的封裝,適用作工作單元,通常用來做並發任務、遍歷、以及回調。下面看一個通知的例子:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
// Notification-handling code goes here.
}
以上是調用addServer方法的例子,不過也可以這麼寫:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification
object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
// Notification-handling code goes here.
}];
}
蘋果官網這個使用Block的例子如果第一次看可能不是那麼好理解,如果仔細的看addServerName的定義發現:
- (id <NSObject>)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0);
其中Block參數定義的時候是這樣的:
(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0)
括號包裹起來的內容,第一個是返回值類型,之後的用用括號包裹^,之後的 話才是傳遞類型,基於以上的理解,可以這麼寫:
void(^MyBlock)(NSNotification *)=^(NSNotification *note){
note=nil;
};
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification
object:nil queue:[NSOperationQueue mainQueue] usingBlock:MyBlock];
Block在蘋果的API文檔中隨處看見其身影,常見的情況任務完成時回調處理,消息監聽回調處理,錯誤回調處理,枚舉回調,視圖動畫、變換,排序,比如說在NSDictionary中的方法中:
- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id key, id obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);
任務完成時候的調用:
- (IBAction)animateView:(id)sender {
CGRect cacheFrame = self.imageView.frame;
[UIView animateWithDuration:1.5 animations:^{
CGRect newFrame = self.imageView.frame;
newFrame.origin.y = newFrame.origin.y + 150.0;
self.imageView.frame = newFrame;
self.imageView.alpha = 0.2;
}
completion:^ (BOOL finished) {
if (finished) {
// Revert image view to original.
self.imageView.frame = cacheFrame;
self.imageView.alpha = 1.0;
}
}];
}
通知機制中的處理:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
opQ = [[NSOperationQueue alloc] init];
[[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted"
object:nil queue:opQ
usingBlock:^(NSNotification *notif) {
NSNumber *theNum = [notif.userInfo objectForKey:@"NumberOfItemsProcessed"];
NSLog(@"Number of items processed: %i", [theNum intValue]);
}];
}
枚舉數組的時候的調用:
NSString *area = @"Europe";
NSArray *timeZoneNames = [NSTimeZone knownTimeZoneNames];
NSMutableArray *areaArray = [NSMutableArray arrayWithCapacity:1];
NSIndexSet *areaIndexes = [timeZoneNames indexesOfObjectsWithOptions:NSEnumerationConcurrent
passingTest:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *tmpStr = (NSString *)obj;
return [tmpStr hasPrefix:area];
}];
NSArray *tmpArray = [timeZoneNames objectsAtIndexes:areaIndexes];
[tmpArray enumerateObjectsWithOptions:NSEnumerationConcurrent|NSEnumerationReverse
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[areaArray addObject:[obj substringFromIndex:[area length]+1]];
}];
NSLog(@"Cities in %@ time zone:%@", area, areaArray);
也可以寫一個Block在截取字符串,做一些自己需要的事情:
NSString *musician = @"Beatles";
NSString *musicDates = [NSString stringWithContentsOfFile:
@"/usr/share/calendar/calendar.music"
encoding:NSASCIIStringEncoding error:NULL];
[musicDates enumerateSubstringsInRange:NSMakeRange(0, [musicDates length]-1)
options:NSStringEnumerationByLines
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
NSRange found = [substring rangeOfString:musician];
if (found.location != NSNotFound) {
NSLog(@"%@", substring);
}
}];
視圖動畫和轉換中的實踐:
[UIView animateWithDuration:0.2 animations:^{
view.alpha = 0.0;
} completion:^(BOOL finished){
[view removeFromSuperview];
}];
兩個視圖之間的動畫:
[UIView transitionWithView:containerView duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[fromView removeFromSuperview];
[containerView addSubview:toView]
}
completion:NULL];
數組排序的實踐:
NSArray *stringsArray = [NSArray arrayWithObjects:
@"string 1",
@"String 21",
@"string 12",
@"String 11",
@"String 02", nil];
static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch |
NSWidthInsensitiveSearch | NSForcedOrderingSearch;
NSLocale *currentLocale = [NSLocale currentLocale];
NSComparator finderSort = ^(id string1, id string2) {
NSRange string1Range = NSMakeRange(0, [string1 length]);
return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];
};
NSLog(@"finderSort: %@", [stringsArray sortedArrayUsingComparator:finderSort]);