使用XMLParser AFNetworking HTTPClient子类

时间:2011-11-30 09:56:21

标签: iphone objective-c cocoa-touch singleton afnetworking

我正在编写一个查询XML REST Web服务的小型iOS应用程序。正在使用的网络框架是AFNetworking

情况

要查询我将AFHTTPClient子类化的Web服务:

@interface MyApiClient : AFHTTPClient

并且在实现中我将其作为单身人士提供:

+ (MyApiClient *)sharedClient {
    static MySharedClient *_sharedClient = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedClient = [[self alloc] initWithBaseUrl:[NSUrl URLWithString:@"http://url.to.the.webservice"]];
    });

    return self;
} 

并且在initWithBaseURL中我告诉AFNetworking期望XML内容:

[self registerHTTPOperationClass:[AFXMLRequestOperation class]];

现在我可以从我的ViewController调用单例上的getPatch,并在成功块中开始解析我返回的XML。在ViewController中的NSXMLParserDelegate方法中,我可以选择我感兴趣的XML部分,并用它做些事情。

问题

我希望在我的HTTPClient单例中有方法来处理与webservice相关的所有内容,并返回数据模型或模型列表而不是XML。

例如,我想做这样的事情:

ServerModel *status = [[MyApiClient sharedClient] getServerStatus];

然后,ApiClient将在内部调用Web服务,解析XML并返回模型。 我怎样才能做到这一点?通常我会使用一个在解析XML时调用的委托,但是由于ApiClient的单例性质,可能有多个委托?

希望有人能够阐明这一点,谢谢!

2 个答案:

答案 0 :(得分:4)

使用块代替委托。

来自我的ApiClient课程:

- (void)getPath:(NSString *)path 
     parameters:(NSDictionary *)parameters 
        success:(void (^)(id response))success 
        failure:(void (^)(NSError *error))failure 
{   
    NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
    [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
}

-(void)fetchAllUsersSuccess:(void (^)(id))success 
                     failure:(void (^)(NSError *))failure
{
    [self getPath:@"/api/mobile/user/" 
       parameters:nil 
          success:^(id response) {  

                      if([response isKindOfClass:[NSXMLParser class]]){
                          //parse here to new dict
                          success(newDict);
                      } else
                          success(response);

          } failure:^(NSError *error) {
              failure(error);
          }];
}

现在我可以使用它:

ServiceApiClient *apiClient = [ServiceApiClient sharedClient];

[apiClient fetchAllUsersSuccess:^(id dict) {
    for (NSDictionary *object in [dict objectForKey:@"objects"]) {
        [ServiceUser addUserFromDictionary:object
                                 inContext:self.managedObjectContext];
    }
    NSError *error= nil;
    [self.managedObjectContext save:&error];
    if (error) {
        NSLog(@"%@", error);
    }
} failure:^(NSError * error) {
    NSLog(@"%@", error);
}];

答案 1 :(得分:0)

(对这种“类型”答案提前道歉,但我们正在努力寻求更好的解决方案......)

您需要退后一步,仔细考虑您的设计。

你遇到了问题,因为你已经知道你的设计中的某些东西需要是一个单身,但要么:

1)这实际上并不是必需的,

2)可能已经存在为您完成这项工作的事情(例如您正在使用的HTTP库),

3)你把错误的东西当作单身人士,或者你没有将你的设计分成适当的部分以便与单身人士的想法一起使用

那么,你能明确地告诉我为什么要采用单身方法吗?是否只是确保一次只能发生一个网络请求?你的单身对象中是否有任何有状态的概念?然后我会更新这个答案或评论等。

Digression:我还要补充一点,在某些情况下可能真的需要''单身 - 我的意思是确实存在只有一个可能的实例,并且正如你所做的那样,这个机制直接进入你的对象 - 但这不是它。另一种选择是''单例,我指的是你的核心对象实际上这项工作实际上有一个普通的init方法,但是对公共对象的共享访问是通过另一个对象进行的,这是一种实例化/保存共享实例的简单“工厂”。这样做的好处是弱单一的想法是你的代码在不同的上下文中更容易重用 - 例如,你可以决定在以后同时进行多个HTTP请求/会话 - 并且它有时会使编写测试的问题更少。)