2012-04-19 75 views
3

我開發的應用程序是一個與OS X服務器進行通信的iOS客戶端。此應用程序的當前版本執行主線程上的所有網絡邏輯,並且這對我想要執行的操作很好。在iOS上使用單獨的線程進行網絡連接

但是,在下一個版本中,我希望網絡邏輯更加靈活。爲了達到這個目的,我想將一個單獨的線程專用於它,但我不太清楚哪種解決方案適合我的需求。

起初,GCD看起來很不錯,但它似乎只適合在單獨的線程上執行大量工作。我想要做的是在一個單獨的線程上擁有所有的網絡邏輯。 iOS客戶端和OS X服務器之間的連接是持久的,並且所有數據流和處理應該在該單獨的線程上進行。

問題歸結爲,哪種方法最適合這種情況?

編輯:爲了擺脫任何困惑,我使用的連接使用套接字和NSStream實例。我不處理連接到遠程Web服務器。換句話說,AFNetworking和ASIHttpRequest不適合我。

+0

你爲什麼不使用[ASIHTTPRequest(http://allseeing-i.com/ASIHTTPRequest/)或[AFNetworking(http://afnetworking.org) – Lefteris 2012-04-19 09:46:02

+0

僅供參考 - ASIHttpRequest不再是發達。 – 2012-04-19 09:55:02

+0

是的,我知道,但那有什麼問題?現在不行嗎?它是。這就是爲什麼我也建議AFNetworking ... – Lefteris 2012-04-19 11:40:43

回答

5
  1. 您可以創建runloop線程(我們稱之爲NetworkThread),運行下面的代碼:

    while (!self.isCancelled) { 
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
        [pool release]; 
    } 
    
  2. 那麼你可以使用- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait對NetworkThread執行您的網絡請求選擇。

  3. 所有網絡回調將在NetworkThread上調用,然後在NetworkThread上處理您的響應數據,將最終數據推送到主線程,更新UI。

0

AFNetworking非常棒。使用塊和GCD。我寫了一個NetworkClient類,它使得調用它非常簡單。隨意使用它或定製它,但我不保證任何東西:)

API密鑰是可以刪除,如果這不符合您的需要。我將其添加爲爲我的所有網絡請求添加安全性的一種方式。我的Web服務在返回任何內容之前檢查傳入的APIKey的有效性。

另外,你可以在你想要完成的事情上相當靈活。你可以做同步或異步請求,沒有警告就失敗的用戶請求等

基本用法示例:

NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
           @"GetAllParkingLots", @"Command", 
           nil]; 

     [NetworkClient processURLRequestWithURL:nil andParams:params block:^(id obj) { 
      // I check to see what kind of object is passed back, in this case I was expecting an Array 
      if ([obj isKindOfClass:[NSArray class]]) { 
       // Do something with the Array 
       [self processNetworkRequestWithArray:(NSArray *)obj]; 
      } 
     }]; 

NetworkClient.h:

// 
// NetworkClient.h 
// 
// Created by LJ Wilson on 2/18/12. 
// Copyright (c) 2012 LJ Wilson All rights reserved. 
// 

#import <Foundation/Foundation.h> 

extern NSString * const APIKey; 

@interface NetworkClient : NSObject 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
          block:(void (^)(id obj))block; 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
          block:(void (^)(id obj))block; 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
      alertUserOnFailure:(BOOL)alertUserOnFailure 
          block:(void (^)(id obj))block; 

+(void)handleNetworkErrorWithError:(NSError *)error; 

+(void)handleNoAccessWithReason:(NSString *)reason; 

@end 

NetworkClient.m :

// 
// NetworkClient.m 
// 
// Created by LJ Wilson on 2/18/12. 
// Copyright (c) 2012 LJ Wilson All rights reserved. 
// 

#import "NetworkClient.h" 
#import "AFHTTPClient.h" 
#import "AFHTTPRequestOperation.h" 
#import "SBJson.h" 

#warning Set APIKey or set to nil 
NSString * const APIKey = @"YourAPIKEYGoesHere"; 

@implementation NetworkClient 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
          block:(void (^)(id obj))block { 

    [self processURLRequestWithURL:url andParams:params syncRequest:NO alertUserOnFailure:NO block:^(id obj) { 
     block(obj); 
    }]; 
} 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
          block:(void (^)(id obj))block { 
    [self processURLRequestWithURL:url andParams:params syncRequest:syncRequest alertUserOnFailure:NO block:^(id obj) { 
     block(obj); 
    }]; 
} 


+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
      alertUserOnFailure:(BOOL)alertUserOnFailure 
          block:(void (^)(id obj))block { 

#warning Fix default url 
    // Default url goes here, pass in a nil to use it 
    if (url == nil) { 
     url = @"YourDefaultURLGoesHere"; 
    } 

    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:params]; 
    [dict setValue:APIKey forKey:@"APIKey"]; 

    NSDictionary *newParams = [[NSDictionary alloc] initWithDictionary:dict]; 

    NSURL *requestURL; 
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:requestURL]; 

    NSMutableURLRequest *theRequest = [httpClient requestWithMethod:@"POST" path:url parameters:newParams]; 

    __block NSString *responseString = @""; 

    AFHTTPRequestOperation *_operation = [[AFHTTPRequestOperation alloc] initWithRequest:theRequest]; 
    __weak AFHTTPRequestOperation *operation = _operation; 

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
     responseString = [operation responseString]; 

     id retObj = [responseString JSONValue]; 

     // Check for invalid response (No Access) 
     if ([retObj isKindOfClass:[NSDictionary class]]) { 
      if ([[(NSDictionary *)retObj valueForKey:@"Message"] isEqualToString:@"No Access"]) { 
       block(nil); 
       [self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:@"Reason"]]; 
      } 
     } else if ([retObj isKindOfClass:[NSArray class]]) { 
      if ([(NSArray *)retObj count] > 0) { 
       NSDictionary *dict = [(NSArray *)retObj objectAtIndex:0]; 
       if ([[dict valueForKey:@"Message"] isEqualToString:@"No Access"]) { 
        block(nil); 
        [self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:@"Reason"]]; 
       } 
      } 
     } 
     block(retObj); 
    } 
             failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
              NSLog(@"Failed with error = %@", [NSString stringWithFormat:@"[Error]:%@",error]); 
              block(nil); 
              if (alertUserOnFailure) { 
               // Let the user know something went wrong 
               [self handleNetworkErrorWithError:operation.error]; 
              } 

             }]; 

    [operation start]; 

    if (syncRequest) { 
     // Process the request syncronously 
     [operation waitUntilFinished]; 
    } 


} 


+(void)handleNetworkErrorWithError:(NSError *)error { 
    NSString *errorString = [NSString stringWithFormat:@"[Error]:%@",error]; 

    // Standard UIAlert Syntax 
    UIAlertView *myAlert = [[UIAlertView alloc] 
          initWithTitle:@"Connection Error" 
          message:errorString 
          delegate:nil 
          cancelButtonTitle:@"OK" 
          otherButtonTitles:nil, nil]; 

    [myAlert show]; 

} 

+(void)handleNoAccessWithReason:(NSString *)reason { 
    // Standard UIAlert Syntax 
    UIAlertView *myAlert = [[UIAlertView alloc] 
          initWithTitle:@"No Access" 
          message:reason 
          delegate:nil 
          cancelButtonTitle:@"OK" 
          otherButtonTitles:nil, nil]; 

    [myAlert show]; 

} 


@end 
+0

感謝您的精心解答。但是,AFNetworking不是我所期待的,因爲我沒有連接到Web服務器。我在過去的項目中使用了AFNetworking,它的確工作得很好。對於這個應用程序(如問題中提到的),我使用Bonjour和低級套接字API在iOS客戶端和OS X服務器之間進行通信。 – 2012-04-19 11:20:30

相關問題