草庐IT

objective-c - iOS RESTful POST调用在UIWebView中有效,但从线程调用时无效

coder 2024-01-21 原文

我正在尝试在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调用的测试,并且该测试成功进行。

如果需要澄清任何内容或包含更多代码,请告诉我!提前致谢。

最佳答案

通常情况下,您无需在其他线程上运行网络操作。

您需要避免的是在主线程上进行同步操作。这将导致iOS终止您的应用程序,因为它会在网络传输繁忙时停止响应事件。

苹果的建议是在主线程上使用异步操作,而不是在另一个线程上使用同步操作。

使用异步操作将导致网络本身在后台运行。您可以将其视为Apple的专用线程。当iOS认为合适时,将在主线程上以正确的顺序调用您的委托方法,以赶上网络。

使用NSURLConnection

Apple在《 URL加载系统编程指南》 Using NSURLConnection中提供了有关如何使用NSURLConnection的示例。这是一篇简短的文章,其中包含许多简单的代码示例。您应该花几分钟来阅读此内容。

简而言之,这是模式:

  • 为您的响应数据保留一个NSMutableData
  • 清除NSMutableData中的内容didReceiveResponse实例。 (在重定向时,您可能会收到多个didReceiveResponse事件,但您只能使用最后一个的数据。)
  • 将您从didReceiveData接收的数据追加到NSMutableData。不要试图立即处理它;您通常会在一次转移中收到多个didReceiveData事件。
  • connectionDidFinishLoading中,您的数据已完成。在这里,您可以使用它来做一些事情。

  • 当拥有所有数据时,可以将其发送到其他线程,也可以将(更简单的)dispatch_async发送到不在主线程上运行的队列。请参见URL Loading System Programming Guide的清单5,“示例connectionDidFinishLoading:实现”。

    这里的想法是,您开始(或重新启动)累积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可能会更好。

    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现在可以发布到任何版本)。至少值得考虑。

    关于objective-c - iOS RESTful POST调用在UIWebView中有效,但从线程调用时无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10745510/

    有关objective-c - iOS RESTful POST调用在UIWebView中有效,但从线程调用时无效的更多相关文章

    1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    2. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

      我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

    3. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

      如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

    4. ruby - 如何进行排列以有效地定制输出 - 2

      这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

    5. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

      我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

    6. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

      我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

    7. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

      我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

    8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

      如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

    9. java - 从 JRuby 调用 Java 类的问题 - 2

      我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

    10. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

      我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

    随机推荐