首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Objective-C Blocks 完整指南:從語法到代理模式替代實戰

     編輯:關於C

什麼是 Blocks?

Blocks(塊) 是 C 語言層面的閉包,支援捕獲外部變數、作為參數傳遞、延遲執行。Apple 於 OS X 10.6 / iOS 4.0 引入,現為 Grand Central Dispatch (GCD)、動畫 API、網路回調的標準寫法。本質上是「帶有自動捕獲環境的匿名函數」,比傳統 C 函數指標更強大、更安全。

Blocks vs C 函數指標

特性C 函數指標Blocks
捕獲區域變數❌ 需手動傳遞 context 指標✅ 自動捕獲(值複製或 __block 參考)
語法靈活度僅能指向既有函數可內聯定義匿名邏輯
記憶體管理手動ARC 自動管理(需 copy 移至堆區)
型別安全較弱編譯期完整檢查參數/返回型別

語法速查表

1. 型別別名

typedef int (^SumBlock)(int a, int b); // 可重複使用的型別名

2. 宣告與賦值

// 無參無回傳
void (^simpleBlock)(void) = ^{ NSLog(@"Hello Block"); };

// 有參有回傳
int (^addBlock)(int, int) = ^(int a, int b) { return a + b; };

// 使用 typedef
SumBlock sum = ^(int a, int b) { return a + b; };

3. 呼叫

simpleBlock();           // 輸出 Hello Block
int result = addBlock(3, 5); // result = 8

4. __block 修飾詞:打破值捕獲限制

預設 Blocks 以值捕獲外部區域變數(唯讀)。加上 __block 可讓 Block 讀寫同一記憶體位址:

__block int counter = 0;
void (^increment)(void) = ^{ counter++; };
increment(); // counter = 1
increment(); // counter = 2

實戰:用 Blocks 替代 Delegate 實現「狗吠叫通知主人」

同一場景,程式碼更緊湊、就地定義回調邏輯。

Dog.h

#import 
@class Dog;

typedef void (^DogBarkBlock)(Dog *dog, NSInteger count);

@interface Dog : NSObject
@property (nonatomic, assign) NSInteger dogID;
@property (nonatomic, copy) DogBarkBlock barkHandler; // 必須 copy
- (instancetype)initWithID:(NSInteger)id;
@end

Dog.m

#import "Dog.h"

@implementation Dog {
    NSTimer *_timer;
    NSInteger _barkCount;
}
- (instancetype)initWithID:(NSInteger)id {
    self = [super init];
    if (self) {
        _dogID = id;
        _barkCount = 0;
        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                  target:self
                                                selector:@selector(timerFired:)
                                                userInfo:nil
                                                 repeats:YES];
    }
    return self;
}
- (void)timerFired:(NSTimer *)timer {
    _barkCount++;
    if (self.barkHandler) {
        self.barkHandler(self, _barkCount); // 直接呼叫 Block
    }
}
- (void)dealloc {
    [_timer invalidate];
    _timer = nil;
    // ARC 自動釋放 barkHandler (copy 的 Block)
}
@end

使用端

Dog *dog = [[Dog alloc] initWithID:1024];
dog.barkHandler = ^(Dog *d, NSInteger count) {
    NSLog(@"[Block 回調] 狗 %ld 第 %ld 次吠叫", (long)d.dogID, (long)count);
};

// 為了讓 Timer 運作,命令列專案需跑 RunLoop
[[NSRunLoop currentRunLoop] run];

記憶體管理黃金法則

  1. 屬性宣告用 copy:Block 建立在棧上,copy 將其複製到堆區,隨物件生命週期釋放。
  2. 避免循環引用:Block 內捕獲 self 時,務必用 __weak 或 __block 弱引用:
    __weak typeof(self) weakSelf = self;
    self.completionHandler = ^{
        [weakSelf doSomething]; // 安全
    };
    
  3. 全域/靜態 Block:編譯器自動置於資料段,無需 copy,但仍建議統一用 copy 習慣。

常見應用場景

  • GCD 非同步任務:dispatch_async(queue, ^{ ... });
  • UIView 動畫:[UIView animateWithDuration:0.3 animations:^{ ... }]
  • 網路請求回調:dataTaskWithRequest:completionHandler:^(data, resp, err){ ... }
  • 集合遍歷:[array enumerateObjectsUsingBlock:^(obj, idx, stop){ ... }]

總結

Blocks 讓 Objective-C 擁有了現代語言的閉包能力,極大簡化了非同步、回調、集合操作的程式碼。掌握 copy、__block、弱引用破環三大記憶體管理要訣,即可安全、高效地在專案中大量使用 Blocks,甚至完全替代簡單的 Delegate 模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved