原代碼嘗試在同步方法中返回異步 Block 執行結果:
-(NSInteger)globalRecord {
__block NSInteger globalRecord = 0;
[GKLeaderboard loadLeaderboardsWithCompletionHandler:^(NSArray *leaderboards, NSError *error) {
// ... 異步嵌套 ...
[globalTaps loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if ([scores count] != 0) {
globalRecord = topScore.value; // 42
}
}];
}];
return globalRecord; // 此時異步未完成,返回 0
}
**核心誤區**:異步操作 (網絡請求、Block 回調) 在當前線程**不會阻塞等待**,方法會立即返回,此時回調尚未執行。
將返回值改為參數傳遞給回調 Block:
// 1. 方法簽名改為 void,增加 completion 參數
- (void)fetchGlobalRecordWithCompletion:(void (^)(NSInteger record))completion {
[GKLeaderboard loadLeaderboardsWithCompletionHandler:^(NSArray *leaderboards, NSError *error) {
GKLeaderboard *globalTaps = nil;
for (GKLeaderboard *lb in leaderboards) {
if ([lb.category isEqualToString:kGlobalLeaderboard]) {
globalTaps = lb;
break;
}
}
if (globalTaps) {
[globalTaps loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
NSInteger record = 0;
if (scores.count > 0) {
GKScore *topScore = scores[0];
record = topScore.value;
}
// 2. 在主線程回調結果 (UI 更新通常需主線程)
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(record);
});
}
}];
} else {
if (completion) completion(0);
}
}];
}
// 3. 調用示例
[self fetchGlobalRecordWithCompletion:^(NSInteger record) {
NSLog(@"最高分: %ld", record); // 42
// 更新 UI、存儲等後續邏輯
}];
void,結果通過 Block 參數傳遞。dispatch_async(dispatch_get_main_queue(), ...)。(NSInteger record, NSError *error)。使用 PromiseKit、RxSwift 或 Swift async/await (iOS 13+) 可將回調地獄扁平化:
// PromiseKit 示例
- (Promise<NSInteger>)fetchGlobalRecord {
return [GKLeaderboard loadLeaderboards].then(^(NSArray *leaderboards) {
GKLeaderboard *global = [leaderboards firstObjectMatching:^(GKLeaderboard *lb) {
return [lb.category isEqualToString:kGlobalLeaderboard];
}];
return [global loadScores];
}).then(^(NSArray *scores) {
return @(scores.firstObject.value);
});
}
// 調用
[self fetchGlobalRecord].done(^(NSInteger record) {
NSLog(@"%ld", record);
}).catch(^(NSError *error) {
// 錯誤處理
});
func fetchGlobalRecord() async throws -> Int {
let leaderboards = try await GKLeaderboard.loadLeaderboards()
guard let global = leaderboards.first(where: { $0.category == kGlobalLeaderboard }) else { return 0 }
let scores = try await global.loadScores()
return scores.first?.value ?? 0
}
// 調用
Task {
do {
let record = try await fetchGlobalRecord()
print("最高分: \(record)")
} catch {
print("錯誤: \(error)")
}
}
**異步操作無法通過返回值獲取結果**。必須採用**回調 Block、Delegate、Promise、async/await** 等異步編程模式。Objective-C 時代標準做法是 **Completion Handler 回調**,並注意線程切換與錯誤傳遞。