我正在尝试在iOS应用中创建一个身份验证系统,允许用户登录并注册,如果他们还没有帐户。我昨天完全启动并运行了登录系统,但是当我为注册系统设置代码时,代码甚至不会ping服务器。然后我再次尝试测试登录系统,代码现在也不会ping服务器。
RegistrationTableViewController的相关代码(它是一个自定义TVC,其中包含某些单元格中的文本字段 - 例如,考虑创建新日历事件的视图):
- (IBAction)signUpButtonPressed {
// Get the values out of the text fields that the user has filled out.
NSString *email = self.emailTextField.text;
NSString *firstName = self.firstNameTextField.text;
NSString *lastName = self.lastNameTextField.text;
NSString *password = self.passwordTextField.text;
// Assuming that sign-up could potentially take a noticeable amount of time, run the
// process on a separate thread to avoid locking the UI.
dispatch_queue_t signUpQueue = dispatch_queue_create("sign-up authenticator", NULL);
dispatch_async(signUpQueue, ^{
// self.brain refers to a SignUpBrain property. See the code for the class below.
[self.brain signUpUsingEmail:email firstName:firstName lastName:lastName
andPassword:password];
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"ShowMainFromSignUp" sender:self];
});
});
dispatch_release(signUpQueue);
}
SignUpBrain的相关代码:
- (void)signUpUsingEmail:(NSString *)email firstName:(NSString *)firstName
lastName:(NSString *)lastName andPassword:(NSString *)password {
self.email = email;
self.firstName = firstName;
self.lastName = lastName;
self.password = password;
// Handle sign-up web calls.
NSMutableURLRequest *signUpRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL
URLWithString:@"URL GOES HERE"]]; // obviously there's an actual URL in real code
NSString *postString = [NSString stringWithFormat:@"uname=%@&pw=%@&fname=%@&lname=%@",
email, password, firstName, lastName];
//NSLog(postString);
[signUpRequest setHTTPMethod:@"POST"];
[signUpRequest setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *signUpConnection =
[NSURLConnection connectionWithRequest:signUpRequest delegate:self];
[signUpConnection start];
// Store any user data.
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
self.signUpResponse = data;
NSError *error;
NSDictionary *jsonLoginResults = [NSJSONSerialization JSONObjectWithData:data
options:0 error:&error];
if (error) {
NSLog(error.description);
}
NSLog(jsonLoginResults.description);
// Return whether the user has successfully been registered.
// If success is 1, then registration has been completed successfully. 0 if not.
if ([jsonLoginResults objectForKey:@"status"]) {
NSLog(@"Success!");
}
}
我还要注意,我创建了一个在UIWebView中使用这些相同Web调用的测试,并且它可以成功运行。
如果我需要澄清任何内容或包含更多代码,请告知我们!提前谢谢。
答案 0 :(得分:1)
几年前我写了一篇关于这个确切问题的博客文章,所以它可能有点过时了:http://www.sortedbits.com/nsurlconnection-in-its-own-thread
很高兴知道NSURLConnection确实正常启动,但是没有收到代理调用。当您将NSRunLoop放在那里时,它确保您的连接不会超出该线程中的范围。
答案 1 :(得分:1)
在正常情况下,您不需要在其他线程上运行网络操作。
您需要避免的是主线程上的同步操作。这将导致iOS终止您的应用程序,因为它会在网络传输繁忙时停止响应事件。
Apple的建议是在主线程上使用异步操作,而不是在另一个线程上进行同步操作。使用异步操作将导致网络本身在后台运行。您可以将此视为Apple的专用线程。您的委托方法将在主线程上以正确的顺序调用,以便在iOS确定合适的情况下赶上网络。
Apple在URL加载系统编程指南Using NSURLConnection中包含了如何使用NSURLConnection
的示例。这是一篇简短的文章,充满了简单的代码示例。你应该花几分钟时间阅读这篇文章。
简而言之,这是模式:
NSMutableData
。NSMutableData
中的内容didReceiveResponse
实例。 (您在重定向时可能会收到多个didReceiveResponse
个事件,但您应该只使用上一个事件中的数据。)didReceiveData
收到的数据附加到NSMutableData
。不要试图立即处理它; 通常会收到多个didReceiveData
个事件进行一次转移。connectionDidFinishLoading
中,您的数据已完成。在这里,你可以用它做点什么。当您拥有所有数据时,您可以将其发送到不同的线程或(更简单)dispatch_async
发送到未在主线程上运行的队列。请参阅清单5,URL Loading System Programming Guide的“示例connectionDidFinishLoading:implementation”。
这里的想法是,您开始(或重新启动)在didReceiveResponse:
中累积数据,在didReceiveData:
中附加数据,并实际对connectionDidFinishLoading:
中的数据执行某些操作。
可以在另一个线程上运行NSURLConnection
,当然。该线程需要使用运行循环来从网络接收委托事件。但除非有某种原因你需要一个单独的线程,否则使用异步网络是Apple的解决方案。
使用NSURLConnection
要求类成员在传输数据时累积数据。这意味着如果你要同时进行多次转移,你需要更复杂的东西。可能是一个驱动NSURLConnection
的包装类,并将每个响应分开。当你编写这个包装类时,你可能已经编写了一个简单的AFHTTPRequestOperation
版本,它是AFNetworking的一部分。
假设您一次只进行一次转移,代码看起来有点像这样:
- (void)signUpUsingEmail:(NSString *)email firstName:(NSString *)firstName
lastName:(NSString *)lastName andPassword:(NSString *)password {
// set up your connection here, but don't start it yet.
receivedData = [[NSMutableData alloc] init]; // receivedData should be a class member
[signUpConnection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error {
// do something with error here
// if you're not using ARC, release connection & receivedData here
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
dispatch_async(someQueue, ^{
// do something that takes a long time with receivedData here
dispatch_async( dispatch_get_main_queue(), ^{
// go back to your main screen here
});
});
// if you're not using ARC, release connection & receivedData here
}
现在我已经解释了这一切,我将提出一个替代方案。您可能最好使用AFNetworking。
AFNetworking是一个开源的第三方库。它最基本的类将NSURLConnection
包裹在NSOperation
中(因此可以添加到NSOperationQueue
中)。 AFNetworking处理我自动谈到的这些事件。相反,你写一个完成块。当您获得此阻止时,传输已成功或失败。如果失败,则AFHTTPRequestOperation
实例上会出现错误。如果成功,您可以使用AFHTTPRequestOperation
实例上的数据。
(注意:我相信AFHTTPRequestOperation
实际上是从另一个线程运行连接。但是,它是编写良好且经过良好测试的代码。执行此操作没有任何“错误”,它更难以启动通常是不必要的。但是如果你的图书馆为你做了,为什么不呢?)
AFNetworking提供了一些NSURLConnection
没有的HTTP逻辑。使用AFNetworking,您只需使用AFHTTPRequestOperation
并设置完成块。所有这些都变成了:
HTTPOperation = [[AFHTTPRequestOperation alloc] initWithRequest: URLRequest];
HTTPOperation.completionBlock = ^{
dispatch_async(someQueue, ^{
// get possible error or content from HTTPOperation
}
};
[HTTPOperation start];
过去,我直接使用NSURLConnection编写。但最近,我更频繁地使用AFNetworking。与其他一些库不同,它与NSURLConnection的形状并不完全不同。事实上,它使用的是NSURLConnection,只是包含在NSOperation中(希望Apple现在能够获得任何版本)。值得考虑的是,至少。
答案 2 :(得分:0)
NSURLConnection需要一个默认情况下在辅助线程上不可用的runloop。如果需要在辅助线程上创建连接,请添加在NSDefaultRunLoopMode中运行的runloop。
在创建NSURLConnection对象之前使用以下代码。 “finished”是一个BOOL类型的iVar,当连接加载完成时应该更新为YES。
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!finished);
希望这有帮助。
答案 3 :(得分:0)
每个线程都有一个关联的runloop。 NSURLConnection的委托方法被触发需要runloop。
在- (void)signUpUsingEmail:...
方法之后的[signUpConnection start];
方法中,在该线程上运行URL连接(由GCD创建和管理),这样的runloop -
[signUpConnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];