我对两件事感到好奇:
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
我想知道在设计这些问题时是否存在通用模式。 关于这个问题的任何部分,我都会很高兴。
答案 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"];
希望它有所帮助!