代码之家  ›  专栏  ›  技术社区  ›  nekno

iOS设计:在库中使用委托模式

  •  2
  • nekno  · 技术社区  · 14 年前

    我有一个库项目,它使用ASIHTTPRequest发出URL请求并解析响应。这个库将由一个单独的iPhone应用程序项目使用。

    如果我的iPhone控制器代码响应一个touch事件,然后调用库来发出URL请求,那么如何最好地异步执行请求?

    在库中,如果我对异步请求使用委托模式,如ASIHTTPRequest示例代码中所示,如何将库中的数据返回到iPhone控制器中的调用代码中?

    如果我使用库中的ASIHTTPRequest进行同步URL请求,那么将iPhone控制器对库的调用放在单独的线程上以避免绑定UI线程的最简单方法是什么?

    2 回复  |  直到 14 年前
        1
  •  2
  •   Tommy    14 年前

    我不是ASIHTTPRequest专家(NSURLRequest一直对我很好),但是从代码的快速插入来看,您似乎会使用它的delegate和didffinishselector属性让它有人告诉它URL请求何时完成。例如:

    - (void)startURLRequest
    {
        ASIHTTPRequest *myRequest;
    
        /* code to set the request up with your target URL, etc here */
    
        myRequest.delegate = self;
        myRequest.didFinishSelector = @selector(HTTPRequestDidFinish:);
    
        /* ... */
    
        [myRequest startAsynchronous];
    }
    
    - (void)HTTPRequestDidFinish:(ASIHTTPRequest *)request
    {
        NSLog(@"Request %@ did finish, got data: %@", request, request.data);
        [myTargetForData didReceiveData:request.data fromURL:request.originalURL];
    }
    

    Apple明确建议您使用内置的runloop样式机制进行异步HTTP获取,而不是单独的线程。使用单独的线程可能会导致更差的性能,至少在电池寿命和/或设备热量方面,即使它仍然足够快。

    也就是说,作为一个学习点,到目前为止,将某个东西切换到单独的线程并将其报告回主线程(记住:UIKit对象可能只从主线程发送消息)的最快方法是更改以下内容:

    - (void)postResult:(NSString *)result
    {
        instanceOfUILabel.text = result;
    }
    
    - (void)doExpensiveOperationOn:(NSString *)source
    {
         /* lots of expensive processing here, and then... */
         [self postResult:result];
    }
    
    - (IBAction)userWantsOperationDone:(id)sender
    {
         [self doExpensiveOperationOn:@"some value or another"];
    }
    

    进入这个:

    - (void)postResult:(NSString *)result
    {
        instanceOfUILabel.text = result;
    }
    
    - (void)doExpensiveOperationOn:(NSString *)source
    {
         /* we're on a thread without an autorelease pool now, probably we'll want one */
         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
         /* lots of expensive processing here, and then... */
    
         /* in this simplified example, we assume that ownership of 'result' is here on this thread, possibly on the autorelease pool, so wait until postResult has definitely finished before doing anything that might release result */
         [self performSelectorOnMainThread:@selector(postResult:) withObject:result waitUntilDone:YES];
    
         [pool release];
    }
    
    - (IBAction)userWantsOperationDone:(id)sender
    {
         [self performSelectorOnBackgroundThread:@selector(doExpensiveOperationOn:) withObject:@"some value or another"];
    }
    

    不过,如果不考虑线程的话,可能会产生一百万个并发错误,在这个例子中,一个明显的问题是,无论触发IBAction的是什么,都可能在doExpensiveOperationOn完成之前多次触发它。多线程并不是一件容易被攻破的事情。

        2
  •  1
  •   nekno    14 年前

    在处理每个响应的最后,我将解析的响应(NSString*或NSArray*)分配给库对象的属性,而不是返回值。

    加载iOS视图控制器委托时,我使用 Key-Value Observing . 当解析响应并将其分配给库中的属性时,observeValueForKeyPath:ofObject:change:context:method在我的视图控制器委托的代码中被调用,从中我可以知道哪些属性被更改了,因此需要更新哪些UI。