2013-01-11 48 views
-1

我目前正在實施從應用程序到我的web服務的連接,此刻我想弄清楚什麼是正確的方式做到這一點。我決定使用AFNetworking庫進行連接,並通過AFNetworking處理JSON輸出。我在這裏讀到,實現這種異步的最佳方式是使用回調委託。這裏是我的兩個班級的鏈接。我真的很喜歡我的實施,特別是要改進什麼。這是正確的方式來消費與AFNetworking的網絡服務

ViewController

WebServiceClass

代碼:

#import "SLLoginViewController.h" 

@interface SLLoginViewController() 

@end 

@implementation SLLoginViewController 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) 
    { 
    } 
    return self; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    sharedWebService = [SLWebService sharedWebService]; 
    [sharedWebService setDelegate:self]; 
    [sharedWebService login:@"[email protected]" withPassword:@"12345"]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
} 

- (void)requestFinished:(NSString *)name withResult:(NSDictionary *)result andError:(NSError *)error 
{ 
    NSLog(@"%@", result); 
} 
@end 

的WebService

#import <Foundation/Foundation.h> 
#import "AFNetworking.h" 

@class SLWebService; 

@protocol SLWebServiceDelegate <NSObject> 

@required 
- (void)requestFinished:(NSString *)name withResult:(NSDictionary *)result andError:(NS 

Error *)error; 

@end 

@interface SLWebService : NSObject 
{ 
    NSURL *baseURL; 
    AFHTTPClient *client; 
} 
@property id <SLWebServiceDelegate> delegate; 

+ (id)sharedWebService; 

- (void)login:(NSString *)email withPassword:(NSString *)password; 

- (NSError *)generateError:(NSString *)description domain:(NSString *)domain; 

@end 

#import "SLWebService.h" 

@implementation SLWebService 

@synthesize delegate; 

+ (id)sharedWebService 
{ 
    static SLWebService *sharedWebService = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     sharedWebService = [[self alloc] init]; 
    }); 
    return sharedWebService; 
} 

-(id)init 
{ 
    self = [super init]; 

    if(self) 
    { 
     baseURL = [[NSURL alloc] initWithString:@"http://www.domain.de/"]; 
     client = [[AFHTTPClient alloc] initWithBaseURL:baseURL]; 
    } 

    return self; 
} 

-(void)login:(NSString *)email withPassword:(NSString *)password 
{ 
    NSDictionary *params = @{@"email":email, @"password":password}; 
    NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"login.php" parameters:params]; 

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request 
    success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) 
    { 
     NSString *result = [JSON objectForKey:@"result"]; 
     if ([result isEqualToString:@"fail"]) 
     { 
      [[self delegate] requestFinished:@"login" withResult:nil andError:[self generateError:[JSON objectForKey:@"reason"] domain:@"de.Searchlight.WebServiceError"]]; 
     } 
     else 
     { 
      NSDictionary *dic = @{@"firstname":[JSON objectForKey:@"firstname"], @"lastname":[JSON objectForKey:@"lastname"], @"gender":[JSON objectForKey:@"gender"]}; 
      [[self delegate] requestFinished:@"login" withResult:dic andError:[self generateError:[JSON objectForKey:@"reason"] domain:@"de.Searchlight.WebServiceError"]]; 
     } 
    } 
    failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *err, id JSON) 
    { 
     [[self delegate]requestFinished:@"login" withResult:nil andError:err]; 
    }]; 

    [operation start]; 
} 

-(NSError *)generateError:(NSString *)description domain:(NSString *)domain 
{ 
    NSError *error; 
    NSDictionary *userInfo = @{NSLocalizedDescriptionKey : description}; 
    error = [NSError errorWithDomain:domain code:200 userInfo:userInfo]; 
    return error; 
} 
@end 
+0

在您的問題中發佈您的代碼,而不是鏈接到pastebin。否則,您可能會冒你的問題被降低並關閉。詳細信息請參見[faq]。 – dandan78

回答

1

AFNetworking是一個不錯的選擇!我建議使用塊,保持登錄請求&結果處理在一起。它也會簡化和縮短代碼。

然後,像AFNetworking的Getting Started在最後表明,這是一個好主意,子類AFHTTPCLIENT

一般說明:正如奇妙的Objective-C Phrasebook所示,可以使用語言的+initialize在沒有GCD的情況下創建單例。共享變量通常是一個靜態的,而不是一個實例變量。

第一部分看起來像:

@class SLWebService; 

@interface SLWebService : AFHTTPClient 

+ (SlWebService)sharedWebService; 

- (void)login:(NSString*)email 
    password:(NSString*)password 
     success:(void (^)(AFHTTPRequestOperation* operation, NSDictionary* response))success 
     failure:(void (^)(AFHTTPRequestOperation* operation, NSError* error))failure; 

@end 

#import "SLWebService.h" 

@implementation SLWebService 

static SLWebService* sharedWebService; 

+ (void)initialize 
{ 
    if ([SLWebService class] == self) 
    { 
     sharedWebService = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.domain.de/"]]; 

     // Let AFNetworking do conversion to/from JSON. 
     [sharedWebService setParameterEncoding:AFJSONParameterEncoding]; 
     [sharedWebService setDefaultHeader:@"Accept" value:@"application/json"]; 
     [sharedWebService registerHTTPOperationClass:[AFJSONRequestOperation class]]; 
    } 
} 

+ (id)allocWithZone:(NSZone*)zone 
{ 
    if (sharedWebService && [SLWebService class] == self) 
    { 
     [NSException raise:NSGenericException format:@"Duplicate SLWebService singleton creation"]; 
    } 

    return [super allocWithZone:zone]; 
} 

+ (SLWebService*)sharedWebService 
{ 
    return sharedWebService; 
} 

... 

作爲最後一個題外話的話:我不喜歡蘋果/ Xcode的建議,使用-initWithNibName::的視圖控制器,因爲這保持外的XIB名類。你幾乎不需要使用不同的XIB進行初始化,因此我寧願在'-init'中指定XIB。像這樣:

- (id)init 
{ 
    if (self = [super initWithNibName:@"SLLoginView" bundle:nil]) 
    { 
    } 

    return self; 
} 

乾杯,希望這有助於!

+0

好的,謝謝你的建議,但我仍然對你使用塊的含義感到好奇。在這種情況下使用委託的方式是錯誤的嗎?我的ViewController和我的WebService之間的溝通是我爭取最多的地方。因爲稍後許多不同的視圖控制器正在訪問WebService。 – digga

+0

作爲一種風格,街區似乎更好/更好。使用委託,您最終將獲得一些其他方法,這些方法也會從調用Web-API的位置移除。 –

+0

想象一下,您需要在用戶的按鈕點擊加載網頁內容。使用塊可以調用你自己的'AFHTTPClient'子類方法(例如'-getXyzContent ::')。在成功塊中,這是該方法調用的一部分,您可以在視圖中顯示接收到的內容。在錯誤塊中,你會通知用戶。 換句話說:使用塊時,您將擁有自包含的「AFHTTPClient」子類方法,您可以在代碼中的任何位置使用這些方法,包括視圖控制器。您可以像用戶已經完成的那樣,在用戶操作代碼,'-init'或'-viewDidLoad'中調用這些方法。 這有道理嗎? –

相關問題