0

我有一个关于在 iOS/Objective-C 中传递数据的问题。我刚开始创建一个连接网站并从网站获取数据的应用程序,现在我遇到了问题。

我的默认和根视图控制器被称为ViewController. 它具有基本的登录 UI 视图:2 个文本字段和一个按钮。

当按钮被点击/触摸时,ViewController调用另一个类的方法,称为LoginService. 现在LoginService处理与网站的连接。我连接到网站并从中获取数据没有问题,但是将获取的数据(现在作为 NSDictionary 处理)返回到ViewController.

我尝试的第一件事是在其中创建一个 setter 方法,ViewController将实例变量设置userProfile为传递给它的 NSDictionary。然而,它失败了。我尝试connectionDidFinishLoadingLoginService.

这可能是一个愚蠢的问题,但我不知道如何在单击按钮后将获取的 NSDictionary 从 LoginService 传递给 ViewController。我需要块、队列或其他东西吗?我的意思是,例如,我需要在我的登录按钮下方设置一个标签,以显示登录用户的名称。我该如何执行此操作?

希望可以有人帮帮我。我将不胜感激。

4

3 回答 3

1

要考虑的两种模式:委托和阻塞。Block 的编码速度更快,我通常更喜欢将它委托给网络操作。要使用块,请以这种方式编写登录服务:

// LoginService.h

- (void)login:(NSString *)username completion:(void (^)(NSDictionary *, NSError *))completion;

听起来你在这里使用 NSURLConnection 委托模式,所以我会假设。请意识到 NSURLConnection 还提供了一个很好的一次性块方法来执行请求。

// LoginService.m

@property (copy, nonatomic) void (^completion)(NSDictionary *, NSError *);


- (void)login:(NSString *)username completion:(void (^)(NSDictionary *, NSError *))completion {

    // copy the block when the request begins
    self.completion = completion;

    // start your request, as you have it now
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    NSDictionary *dictionary = // parse the data you collected into a dictionary

    // invoke the block with the result
    self.completion(dictionary, nil);
    self.completion = nil;
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {

    self.completion(nil, error);
    self.completion = nil;
}

在调用它之后处理块(将其设置为 nil)是有礼貌的,因此它不会保留调用上下文的任何部分。

于 2013-10-31T00:52:09.557 回答
1

基本上你需要 ViewController 有一个公共方法,当 LoginService 完成它的工作时可以调用它,并且 NSDictionary 将是这个方法的一个参数。LoginService 需要返回 ViewController 的引用才能调用此方法,因此在 LoginService 上定义一个公共属性,该属性将保存一个 ViewController 引用 - 并在实例化 LoginService 后设置它。

当然,如果您希望 LoginService 更具可重用性,并且不专门与 ViewController 绑定,那么委托是可行的方法。LoginService 将定义 LoginServiceDelegate 协议以及在完成时调用的方法。然后 ViewController 将实现 LoginServiceDelegate 协议。LoginService 上的公共属性成为 LoginServiceDelegate 引用,因此 LoginService 不再需要导入 ViewController。这样ViewController依赖于LoginService,而LoginService不依赖于ViewController。

于 2013-10-31T00:10:07.523 回答
1

由于 danh 已经解释了这样做的块模式,我将尝试解释委托模式。使这项工作的步骤:

LoginService.h

在 LoginService 中创建一个协议定义,如下所示:

    @protocol LoginServiceDelegate

    -(void)applicationLoggedIn:(NSMutableDictionary*) responseData;

    @end

现在添加一个持有这个委托的成员指针并为此添加一个属性

    @interface LoginService {

        id<LoginServiceDelegate>delegate;
    }
    @property (nonatomic, assign) id <LoginServiceDelegate> delegate;

LoginService.m

一旦你得到 login in 的响应connectionDidFinishLoading,只需调用如下的委托方法:

    if ([delegate respondsToSelector:@selector(applicationLoggedIn:)]) {
            [delegate applicationLoggedIn:responseDict];
    }

LoginViewController.h

现在要在你的 中使用它LoginViewController,你需要实现这个协议

    #import "LoginService.h"
    @interface LoginViewController<LoginServiceDelegate>

LoginViewController.m

将 LoginService 的委托分配给 LoginViewController

    LoginService* loginService = [[LoginService alloc]init];
    loginService.delegate = self; 

将协议方法实现为:

    -(void)applicationLoggedIn:(NSDictionary*)response{

    }

希望这可以帮助。

于 2013-10-31T04:36:20.833 回答