我有一个带有单个方法的类,它使用URLConnection将序列化的NSDictionary发送到某个URL的脚本,然后调用完成块.以下是该方法的代码:
- (void)sendDictionary:(NSDictionary *)dictionary toScript:(NSString *)scriptName completion:(void (^) (id response))completionBlock { ...Serialize data and add it to an NSURLRequest request... H2URLConnection *connection = [[H2URLConnection alloc]initWithRequest:request]; //Define a semaphore to block execution of later statements until the signal is received. dispatch_semaphore_t sem = dispatch_semaphore_create(0); [connection setCompletionBlock:[^(id obj, NSError *err) { if (!err) { //Catch the server response NSString *receivedString = [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding]; NSLog( @"ChecklistAppNetworkManager received string: %@", receivedString); //Convert the JSON response into an NSDictionary NSError *otherError; id deserializedJSON = [NSJSONSerialization JSONObjectWithData:obj options:kNilOptions error:&otherError]; if (otherError) { NSLog(@"ChecklistAppNetworkManager JSON Error: %@", otherError.description); } [completionBlock invoke]; NSLog(@"ChecklistAppNetworkManager JSON Response: %@", deserializedJSON); //Dispatch the semaphore signal so that the main thread continues. dispatch_semaphore_signal(sem); } else { NSLog(@"ChecklistAppNetworkManager encountered an error connecting to the server: %@", [err description]); } }copy]]; //Finalize and initate the connection. [connection start]; //Since block is dispatched to main queue, stall with a loop until the semaphore signal arrives. while (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; } }
我试图在另一个类中调用此类的实例,其中定义了完成块.这是我得到EXC_BAD_ACCESS的代码:
- (void)doSomeServerTask { H2ChecklistAppNetworkManager *currentNetworkManager = ((H2AppDelegate *)[[UIApplication sharedApplication]delegate]).networkManager; //Instantiate class where that method is defined NSMutableDictionary *dictonary = [NSMutableDictionary dictionary]; ...populate dictionary... [currentNetworkManager sendDictionary:dictionary toScript:@"script.php" completion:[^(id response) { //THIS iS THE LINE WHERE THE BAD ACCESS OCCURS NSLog(@"LoginViewController received response: %@", response); } copy]]; }
任何帮助,将不胜感激!
在completionBlock
对方法接受一个参数,但你调用带块invoke
方法.更可能的是,崩溃是因为运行时试图保留内存中应该是该参数的任何垃圾.
但是,您确实需要完全重构此代码.阻止主事件循环是不好的.MEL上运行子runloop甚至更糟; 它改变了调度队列处理语义工作的方式,并可能导致病态性能不良或行为不良.
你应该转向一个真正的异步模型.如果应用程序在完成这些查询之前无法继续,则会设置阻止进度的模式指示器.
为此,您将代码松散地构造为:
•将用户界面置于"加载..."或其他模态状态
•使用完成处理程序执行数据的异步请求
•在完成处理程序中,将"更新UI"请求分派给主队列
•在"更新UI"时,拆除模态"loading ...."UI并更新用户的显示
没有必要阻止主事件循环来执行任何此操作.