iOS - API对象和控制器之间的通信

时间:2014-05-22 08:03:33

标签: ios json nsurlconnection nsnotification

我对两件事感到好奇:

1 是否有效且易于扩展的方式来设计与API通信的对象与视图控制器之间的通信

2 如何设计通信对象本身(如何设计可扩展的方法,...)

(下面我提到的方法很麻烦,我知道,但最后期限很疯狂,直到现在我还没有时间考虑它。)

让我介绍一下我正在处理的任务:

我必须根据与API的通信编写2-3个应用程序。 API响应了大约10-15种不同的方法(通过http POST发送,产生JSON)。当然,沟通必须是异步的。

我的方法:

因此,所有UIViewControllers都共享了与API(简称​​ apiComm )的对象通信。 apiComm 有10-15个方法,每个方法都是API能够处理的方法;个别请求内容之间存在很大差异。=> 问题2

apiComm 从API收到数据时,它在[NSNotificationCenter defaultCenter]上发布了通知。这意味着,每个想要使用 apiComm 的UIViewController必须为通知注册self,并实现处理传入通知的方法。这种方法变得讨厌,因为一些UIViewController必须处理更多的API请求,... => 问题1

我想知道在设计这些问题时是否存在通用模式。 关于这个问题的任何部分,我都会很高兴。

1 个答案:

答案 0 :(得分:1)

对我而言,我能给这个棘手问题的唯一真正答案或方向是:

  • 一定要使用某种类似抽象类的模式,如@liamnichols指出

  • 如果您正在阅读iOS新版本,那么使用“after ...”块模式(下面的代码中的示例)绝对必要

  • 关于这一点,这是iOS / objective-C https://stackoverflow.com/a/20760583/294884中的绝对关键点..如何使块成为属性

  • 纯粹是IMO,我从来没有找到一个大项目,其中“15项”实际上可以真正合理化。它还没有发生。所以对我们来说最好小心 - 至少 - 打包它以便(以这种或那种方式)你称之为“15项”这样的东西.. CLOUD.NOTES .. CLOUD.PROFILE .. CLOUD.SCORES ..和等等你的其余代码。

  • 当然为网络系统使用单例

  • 获取网络系统的KVO和NSNotifications至关重要

  • 非常重要的是要注意在iOS世界中处理JSON是如此荒谬,如今(幸运的是)“只有15个单独的文件”{这样或那样}真的不错事情,很容易看出它,实际上,关于你可以做出的最明确的合理化。

所以,只是一些混合的想法。最后一点 - 一切都只是转移到parse.com 所以这一切都变得毫无意义,幸运的是:)

这几乎就是“我正在与尚未转移到bAAs的客户合作('不,真的!'),所以我如何保持网络代码整洁......!”嘿。


不能轻松,只需写一个漂亮的单身人士

将其放入任何需要它的应用中。

如今,在iOS中处理JSON简直令人难以置信。所以,我所描述的往往是微不足道的......只有几十行代码。

你的“云”文件将包含这个简单的例程...这个单例将被称为“BLANKS”或类似...它从服务器获取一些“空白”用户文件类型,比如说。

-(void)loadIfNeededThen:(void(^)(void))after
    {
    if ( self.rawStubsFromCloud != nil )
        {
        NSLog(@"good new, blanks are already loaded!!");
        after();
        return;
        }

    [APP huddie]; // (use MBProgressHUD for all spinners)
    APP.hud.labelText = @"Loading file blanks from cloud...";

    dispatch_after_secs_on_main(0.1 ,
            ^{
            [self _refreshThen:
                ^{
                [APP.hud hide:YES];

                NSLog(@"loaded the blanks fine:\n%@\n",
                    [self supplyDisplayStyleString] );

                after();
                }];
            }
        );
    }
-(void)_refresh
    {
    [self _refreshThen:nil];
    }

#define uBlanks [NSURL URLWithString:@"http://blah.com/json/blanks"]
-(void)_refreshThen:(void(^)(void))after
    {
    dispatch_async(dispatch_get_main_queue(),
        ^{
        self.rawBlanksFromCloud = [NSData dataWithContentsOfURL:uBlanks];

        [self _doShowAllOnLog];

        after();
        });
    }

值得注意的是,正在转向Parse.com和其他bAAs 。没有其他现实的未来,今年年底之后不会有太多的“服务器端”。

所以在实践中,这些简单的单例变得更加简单 - 它们只是连接到Parse的几行代码。享受!

所以TBC上面的代码示例来自“你们的web服务器”情况。

这是获取“用户文件”的一个示例..(注意用于组装该死的URL调用的方便的例程postStringUser ..我从来没有找到一个非常简洁的方法来做到这一点!)...

-(NSString *)postStringUser:(NSString *)user pass:(NSString *)pass
{
NSString *username = user;
NSString *password = pass;

NSMutableString *r = [NSMutableString stringWithString:@""];

[r appendString:@"command=commandExampleGetFile"];
[r appendString:@"&"];

[r appendString:@"name=blah"];
[r appendString:@"&"];

[r appendString:@"user="];
[r appendString: [username stringByUrlEncoding] ];
[r appendString:@"&"];

[r appendString:@"password="];
[r appendString: [password stringByUrlEncoding] ];

return r;
}

#define yourUrl [NSURL URLWithString:@"http://blah.com/json/blah"]

-(void)fetchTheUsersFiles:(NSString *)user pass:(NSString *)pass then:(void(^)(void))after
{
NSString *postString = [self postStringUser:user pass:pass];
NSLog(@"postString is %@ ", postString );

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:yourUrl];
request.HTTPMethod = @"POST";
request.HTTPBody = [ postString dataUsingEncoding:NSUTF8StringEncoding];
[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField: @"Content-Type"];

[APP huddie]; // use MBProgress everywhere and always at all times in all apps always
APP.hud.labelText = @"Connecting to the cloud...";

// 1 get the data
// 2 make it a jdic
// 3 make it an array of the "files"

[NSURLConnection
  sendAsynchronousRequest: request
  queue: [NSOperationQueue mainQueue]
  completionHandler:^(NSURLResponse *r, NSData *data, NSError *error)
    {
    [APP.hud hide:YES];
    NSLog(@"Done... %@", r);

    self.rawGetFilesFromCloud = data;

    NSError* err;
    NSDictionary* jdic = [NSJSONSerialization
      JSONObjectWithData:self.rawGetFilesFromCloud
      options:kNilOptions
      error:&err];

      //dev only
      NSLog(@"Here's the whole damned jdic, for GetFiles\n%@", jdic);

    if ( ! jdic )
      {
      [APP simpleOK:@"Wrong username or pass? Or no files found."];
      }
    else
      {
      // the user has "logged in" so something like
      STATE.currentUsername = user;
      STATE.currentPassword = pass;
      // naturally you have a STATE singleton, every app needs one

      self.rawArrayFromCloud = [jdic objectForKey:@"data"];

      NSInteger kUserFiles = self.rawArrayFromCloud.count;
      NSString *sayString = [NSString stringWithFormat:
        @"We found %lu files of yours on the damned cloud.", kUserFiles];

      /*
      and for example...
      STATE.fileZero = self.rawArrayFromCloud[0];
      or for example...
      NSDictionary *oneStubDict = self.rawArrayFromCloud[17];
      NSString *subjectName = oneStubDict[@"subjectName"];
      NSString *mainBody = oneStubDict[@"mainBody"];
      NSString *authorField = oneStubDict[@"authorField"];
      */

      [APP simpleOK: sayString
          then:^{ [STATE showFileInterface]; } ];
      }

    if (after) after();
    }];

}

请注意,关键代码仅仅是......

NSMutableURLRequest *request = ...

[NSURLConnection sendAsynchronousRequest: request ...

NSDictionary* jdic = [NSJSONSerialization JSONObjectWithData:result ...

NSArray *theFiles = [jdic objectForKey:@"theFiles"];

NSString *aField = theFiles[13]["coverInfo"]["aField"];

希望它有所帮助!