当我的iOS应用程序启动时,我需要从我的服务器获取一些关键设置(例如:{{3}})。我需要在之前获取此数据我加载用户的数据。
进行此次调用的正确方法是什么,基本上“暂停”应用程序,但仍然没有阻止主线程并且遵守规定?
目前我正在做这个例子,这显然是不正确的,因为它完全阻止了一切:
NSData *myRequestData = [NSData dataWithBytes:[myRequestString UTF8String] length:[myRequestString length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: myURLString]];
[request setHTTPMethod: @"POST"];
[request setHTTPBody:myRequestData];
NSURLResponse *response;
NSError *error;
NSString *returnString = [[NSString alloc] init];
returnString = [[NSString alloc] initWithData:[NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error]
encoding: NSASCIIStringEncoding];
答案 0 :(得分:3)
您可以使用NSURLConnection sendSynchronousRequest
而不是NSURLSessionDataTask
。此外,从iOS 9中不推荐sendSynchronousRequest
。代码如下
NSData *myRequestData = [NSData dataWithBytes:[myRequestString UTF8String] length:[myRequestString length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: myURLString]];
[request setHTTPMethod: @"POST"];
[request setHTTPBody:myRequestData];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
if ([httpResponse statusCode]==200) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString* returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//do whatever operations necessary on main thread
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
//action on failure
});
}
}];
[dataTask resume];
由于它是异步操作,因此不会阻止主线程。就暂停应用而言,您可以在拨打电话之前显示某种活动指示或禁用用户互动。一旦响应出现隐藏指示或启用UI。
答案 1 :(得分:3)
你应该 使用sendSynchronousRequest
。你应该假装该方法不存在。在主线程上调用它是一个非常糟糕的主意,如果远程服务器需要几秒钟的时间来处理您的请求,系统可能会终止您的应用程序。
正如Vishnu建议的那样,请改用NSURLSession
。
如果你想"暂停应用"当您的内容加载时,在加载发生时显示某种模态警报/视图。一种选择是使用UIAlertController
而不添加任何操作,然后在加载完成后调用dismissViewController:animated:
。
我做的另一件事是显示一个完全覆盖屏幕的视图,填充50%不透明的黑色,并在其中放入一个带有进度指示器的视图,加上请等待消息(以及任何你想要的其他化妆品。)50%不透明的视图都会使屏幕的其余部分变暗,并阻止用户点击任何内容,进度指示器让用户知道你的应用程序正在运行。
这两种方法都有效,因为您的下载是异步进行的,因此您可以显示警报或进度指示器,并按预期进行动画制作。
答案 2 :(得分:1)
/ **
您可以使用协议来处理该问题,例如,您可以创建一个连接到您可以使用NSURLSession的URL的类,但您似乎熟悉NSURLConnection。因此,让我们创建一个类,它将连接并从您的URL接收信息,如下所示:
H档
* /
#import <Foundation/Foundation.h>
/* Here is the custome protocol to manage the response at will */
@protocol OnResponseDelegate;
/* Here the class is implementing the protocol to receive the callbaks from the NSURLConnection when the request is processing */
@interface WgetData : NSObject <NSURLConnectionDataDelegate>
@property (strong, nonatomic) id<OnResponseDelegate>handler;
@property (strong, nonatomic) NSMutableData *responseData;
@property (strong, nonatomic) NSURLConnection *connection;
@property (strong, nonatomic) NSMutableURLRequest *request;
-(id)initWithUrl:(NSString*)url postBody:(NSString*)body delegate:(id)delegate;
-(void)execute;
@end
/* here is the real definition of the protocol to manage the response */
@protocol OnResponseDelegate <NSObject>
-(void)onPreStart;
-(void)onResponse:(NSData*)response;
@end
/ * 结束H档
上面的代码使用协议来处理您希望从URL接收的数据。让我们执行它看起来像这样的实现文件:
M档
* /
#import "WgetData.h"
#define TIMEOUT 700
static NSString * const CONTENT_TYPE_VALUE = @"application/json";
static NSString * const CONTENT_TYPE_HEADER = @"Content-Type";
static NSString * const GET = @"GET";
static NSString * const POST = @"POST";
@implementation WgetData
@synthesize handler,responseData,connection,request;
-(id)initWithUrl:(NSString *)url postBody:(NSString *)body delegate:(id)delegate{
NSURL *requestUrl = [NSURL URLWithString:[url stringByAddingPercentEncodingWithAllowedCharacters: NSCharacterSet.URLQueryAllowedCharacterSet]];
[self setRequest:[NSMutableURLRequest requestWithURL:requestUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:TIMEOUT]];
[self setResponseData:[NSMutableData new]];
[self setHandler:delegate];
[request setHTTPMethod:POST];
[request addValue:CONTENT_TYPE_VALUE forHTTPHeaderField:CONTENT_TYPE_HEADER];
[request setHTTPBody: [body dataUsingEncoding:NSUTF8StringEncoding]];
return self;
}
-(void)execute{
//here is the moment to prepare something in your main class before send the request to your URL
[handler onPreStart];
[self setConnection:[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]];
}
/* this method belongs to the implementation of the NSURLConnectionDataDelegate to receive the data little by little */
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.responseData appendData:data];
}
/* this method belongs to the implementation of the NSURLConnectyionDataDelegate that is runned only when the data received is complete */
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
/* if this method happen it means that the data is ready to delivery */
/* sending the information to the class that implements this class through the handler or delegate */
[handler onResponse:responseData];
}
@end
/ *
结束M档
然后你只需要用下一段代码实现这个类 例如,在viewDidLoad
中的ViewController中记得将协议称为委托,以正确的方式实现方法
H文件ViewController示例
* /
#import <UIKit/UIKit.h>
#import "WgetData.h"
@interface ViewController : UIViewController <OnResponseDelegate>
@end
/ *
结束H ViewController文件
M ViewController文件
* /
@interface MainViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
WgetData *getData = [[WgetData alloc] initWithUrl:@"http://myurl.net" delegate:self];
[getData execute];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) onPreStart{
// prepare something before run the request to your URL
}
- (void) onResponse:(NSData *)response{
// receive the data when the data is ready and convert o parse to String or JSON or Bytes or whatever
}
@end
/ *结束M档
因此,在所有这个示例中,您可以管理正确的时刻,当您收到要按照自己的意愿管理的数据时,您的主线程应用程序可以等待您的数据将被接收以备使用。 * /