iOS - communication between API object and controllers

落花浮王杯 提交于 2019-12-04 15:38:40
Fattie

For me the only real answers or direction I can give to this tricky problem is:

  • by all means use some sort of abstract class -like pattern as @liamnichols points out

  • if you are reading this new to iOS, it's absolutely essential to use the "after..." block pattern (examples in the code below)

  • on that point, here's an absolutely critical point in iOS/objective-C https://stackoverflow.com/a/20760583/294884 .. how to make a block a property

  • purely IMO, i've never found a big project where the "15 items" can, in fact, be really truly rationalised. it just has not happened yet. so the best for us it to carefully - at least - package it so that (one way or another) you call the "15 items" something like this .. CLOUD.NOTES .. CLOUD.PROFILE .. CLOUD.SCORES .. and so on from the rest of your code.

  • use a singleton(s) of course for the networking systems

  • it's critical to get with both KVO and NSNotifications for networking systems

  • it's very important to note that it is so absurdly easy to handle JSON in the iOS universe, these days, that (fortunately) having "just 15 separate files" {one way or another} is really not a bad thing and it would be easy to see it as, really, about the most definitive rationalisation you can make.

So, just some mixed thoughts. One final point - everything's just moving to parse.com so this all becomes moot, fortunately :)

It's almost a case of "I'm working with a client who hans't yet moved to a bAAs ('no, really!') so how do I keep networking code tidy ...!" Heh.


Couldn't be easier, just write a nice singleton.

Drop it in any app that needs it.

It's unbelievably easy to handle JSON in iOS these days. So, what I describe is often trivial .. little more than a few dozen lines of code.

Your "cloud" files will contain routines this simple ... this singleton would be called "BLANKS" or similar... it gets some "blank" user file types from the server, let's say.

-(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();
        });
    }

It's worth realising that, everything is moving to Parse.com and other bAAs. There's no other realistic future, there's not going to be much "server side" after the end of this year.

So in practice, these simple singletons become even simpler - they're just the few lines of code to hook up to Parse. Enjoy!

So TBC the above code sample is from an "ye olde web server" situation.

Here's an example of getting "user files" .. (note the handy routine postStringUser for assembling damned url calls .. I've never found a really neat way to do that!)...

-(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();
    }];

}

Note the critical code is little more than ...

NSMutableURLRequest *request = ...

[NSURLConnection sendAsynchronousRequest: request ...

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

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

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

Hope it helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!