【问题标题】:ios - get initial data from server on app startios - 在应用程序启动时从服务器获取初始数据
【发布时间】:2014-05-17 13:16:42
【问题描述】:

我是 iOS 开发新手,正在尝试解决以下问题。

在我的应用程序(与 REST API 对话)中,我想在应用程序开始时向服务器发出初始请求以获取用户信息。我决定使用带有单例方法的单独服务类。它向服务器发出一次请求,然后返回用户实例。

@implementation LSSharedUser

+ (LSUser *)getUser {
  // make request to api server on the first call
  // on other calls return initialized user

  static LSUser *_sharedUser = nil;

  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    LSHTTPClient *api = [LSHTTPClient create];
    [api getUser:^(AFHTTPRequestOperation *operation, id user) {
        _sharedUser = [[LSUser alloc] initWithDictionary:user];
    } failure:nil];
  });

  return _sharedUser;
}

@end

我的问题是从服务器初始化全局数据的正确方法吗?如您所见,请求是异步的(使用 AFNetworking 库),因此它将返回 null,直到请求完成。

这里的另一个问题是,一旦失败(例如连接不良),用户将永远为空。

【问题讨论】:

    标签: ios objective-c singleton global-variables afnetworking-2


    【解决方案1】:

    像这样更新你的代码

     static LSUser *_sharedUser ;
    + (LSUser *)getUser {
      // make request to api server on the first call
      // on other calls return initialized user
    
    if(_sharedUser){
    
    //this will execute only at first time
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        LSHTTPClient *api = [LSHTTPClient create];
        [api getUser:^(AFHTTPRequestOperation *operation, id user) {
            _sharedUser = [[LSUser alloc] initWithDictionary:user];
            return _sharedUser;
        } failure:nil];
      });
    }
    //this will execute 2nd time
      return _sharedUser;
    }
    

    回复线路 -> 问题2)这里的另一个问题是,一旦失败(例如连接错误),用户将永远为空。 ->一旦 _sharedUser 被初始化,用户将获得 _sharedData。但在未初始化共享数据之前,无论何时调用它都会返回 null。

    问题 1 )我的问题是从服务器初始化全局数据的正确方法吗?如您所见,请求是异步的(使用 AFNetworking 库),因此在请求完成之前它将返回 null。

    更好的方法是实现您自己的自定义委托方法。一旦请求被获取或调用时在该委托方法中完成您的工作。 第一次:在请求被获取或失败时执行调用委托方法。 第二次:在 if 块调用委托方法之后。

    【讨论】:

    • 这样当下次调用此方法时,该变量将只能初始化一次。如果我添加的块不会执行...
    • 好的,这个块也将在我的代码中执行一次,但这是一件小事,我实际上是在询问基本方法
    • 这段代码毫无意义:它违背了 dispatch_once 的目的,实现了竞态条件,并且没有解决最初的问题。
    【解决方案2】:

    基本方法需要异步设计。

    假设你有一个异步方法:

    - (void) loadUserWithCompletion:(void (^)(NSDictionary* user, NSError* error))completion;
    

    您在“继续”(完成块)中执行您需要执行的任何内容:

    [self loadUserWithCompletion:^(NSDictionary* params, NSError*error) {
        if (user) {
            User* user = [[User alloc] initWithDictionary:params];
    
            // better we ensure we execute the following on the main thread:
            dispatch_async(dispatch_get_main_queue(), ^{
                self.model.user = user;  
                // If we utilize KVO, observers may listen on self.model.user 
                // which now get a notification.
    
                // We also may to notify the user through an alert:
                ...
    
            });
        }
        else {
            // handler error
        }
    }];
    

    对于异步编程风格,在让用户执行任意任务(例如,选项卡按钮)时,您需要更加小心。您可以考虑禁用需要用户模型的任务。或者,当用户模型尚不可用时显示警报表。

    通常,当用户模型最终可用时,您会使用一些“观察者”技术来获得通知。您可以使用 KVO 或完成处理程序,或者使用一些专门针对这些问题的第三方库(例如 Promise 库)。

    您还应该让用户随时取消该任务。然而,这需要一种更精细的方法,您可以在其中拥有“可取消”的任务,并在其中保存对这些任务的引用,以便能够向它们发送cancel 消息。

    【讨论】:

      猜你喜欢
      • 2016-08-15
      • 2015-08-12
      • 1970-01-01
      • 2018-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多