块内部的变量赋值

variable assignment from inside of a block

我正在使用 Swift 中的 Objective-C。我几乎没有 objective-c 经验。我正在尝试使用 Apple 的示例访问游戏中心并检索前 10 名排行榜分数以在 Swift 中使用。但是,我坚持 objective-c 分配的基础知识,其中将检索到的分数数据传递回调用者。有人可以 post 提供如何处理此问题的代码示例吗?

- (NSArray*) retrieveTopTenScores
{
    GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
    NSArray *temp = nil;
    if (leaderboardRequest != nil)
    {
        leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
        leaderboardRequest.timeScope = GKLeaderboardTimeScopeToday;
        leaderboardRequest.identifier = @"Appid";
        leaderboardRequest.range = NSMakeRange(1,10);
        [leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
            if (error != nil)
            {
                // Handle the error.
                NSLog(@"error in score retrieval");
            }
            if (scores != nil)
            {
               temp = scores; //results to Variable is not assignable (missing __block type specifier)               
            }
        }];
    }
    return temp;

}

您的 return 值将是 nil。这是因为 loadScoresWithCompletionHandler 是一个在后台线程中执行的异步方法,可能需要一些时间来下载数据。在块完成执行之前,执行到达 return temp。为了保存scores数据,可以在class.

中定义一个property
@property (nonatomic,strong) NSArray *topTenScores;

然后您可以在块内分配 属性。如果你想显示你的 toptenscore,你也可以通过从块内部在主线程上调用函数来更新 UI。

[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) 
{
    if (error != nil)
    {
         // Handle the error.
         NSLog(@"error in score retrieval");
    }
    if (scores != nil)
    {
         self.topTenScores = score;
         dispatch_async(dispatch_get_main_queue(), ^{
           // Update the UI on the main thread.
         });
    }
 }];

最好是让主应用程序控制器实现一个处理排行榜接收的方法,例如:

- (void) handleResultsOfLeaderBoardRequest: (NSArray *) leaderboards error: (NSError *error) {
    // store the list in an attribute or process otherwise
}

然后将对此方法的调用作为回调处理程序传递给预期的排行榜请求。

使用块类似于 Javascript 中的编码。结果数据稍后到达——甚至在方法完成执行之后。所以你不能return数组。

loadScoresWithCompletionHandler: 之后缩进的所有内容都将在加载分数/之后/加载分数后发生。您将需要更新该代码块内的 UI。

您正在调用异步方法,因此您应该采用异步模式。现在最常见的约定是使用块(就像 Apple 提供的 loadScoresWithCompletionHandler 方法一样)。最重要的是,与其立即尝试 return NSArray,不如提供您自己的 retrieveTopTenScores 方法一个将在请求完成时调用的块:

最简单的格式如下:

- (void)retrieveTopTenScoresWithCompletionHandler:(void (^)(NSArray *scores, NSError *error))completionHandler
{
    GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];

    if (leaderboardRequest != nil) {
        leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
        leaderboardRequest.timeScope = GKLeaderboardTimeScopeToday;
        leaderboardRequest.identifier = @"Appid";
        leaderboardRequest.range = NSMakeRange(1,10);
        [leaderboardRequest loadScoresWithCompletionHandler:completionHandler];
    }
}

你会这样称呼它:

[self retrieveTopTenScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
    if (scores) {
        // use scores array here
    } else {
        //do something with error here

        NSLog(@"retrieveTopTenScoresWithCompletionHandler error: %@", error);
    }
}];

// but do not try to use `scores` here, because the above runs asynchronously
// and thus, we don't have the scores by the time we get here

请注意,如果您希望该完成块到主队列中的 运行(如果您正在更新 UI 或模型对象,这很重要),那么您可能想要执行类似以下(但只需像上面那样称呼它):

- (void)retrieveTopTenScoresWithCompletionHandler:(void (^)(NSArray *scores, NSError *error))completionHandler
{
    GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];

    if (leaderboardRequest != nil) {
        leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
        leaderboardRequest.timeScope = GKLeaderboardTimeScopeToday;
        leaderboardRequest.identifier = @"Appid";
        leaderboardRequest.range = NSMakeRange(1,10);
        [leaderboardRequest loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                completionHandler(scores, error);
            });
        }];
    }
}