我有一个关于在iOS / Objective-C中传递数据的问题。我刚开始创建一个连接并从网站获取数据的应用程序,现在我遇到了问题。
我的默认和根视图控制器名为ViewController
。它具有基本的登录UI视图:2个文本字段和一个按钮。
单击/触摸按钮后,ViewController
会调用另一个名为LoginService
的类中的方法。现在LoginService
处理与网站的连接。我没有问题连接到网站并从中获取数据,但我将问题(现在作为NSDictionary处理)返回到ViewController
时出现问题。
我尝试的第一件事是在ViewController
中创建一个setter方法,将实例变量userProfile
设置为传递给它的NSDictionary。然而,它失败了。我尝试在connectionDidFinishLoading
的NSURLConnectionDataDelegate方法LoginService
中使用它。
这可能是一个愚蠢的问题,但我不知道如何在单击按钮后将获取的NSDictionary从LoginService传递给ViewController。我需要块,队列还是别的什么?我的意思是,例如,我需要在登录按钮下面设置一个标签,用于登录用户的名称。如何执行此操作?
希望有人可以帮助我。我非常感激。
答案 0 :(得分:1)
基本上你需要ViewController有一个公共方法,LoginService在完成它的工作时可以调用它,NSDictionary将是这个方法的参数。 LoginService需要一个返回ViewController的引用才能调用此方法,因此在LoginService上定义一个公共属性,它将保存一个ViewController引用 - 并在实例化LoginService后设置它。
当然,如果您希望LoginService更具可重用性,并且没有专门与ViewController绑定,那么委托就是可行的方法。 LoginService将使用要在完成时调用的方法定义LoginServiceDelegate协议。然后ViewController将实现LoginServiceDelegate协议。 LoginService上的公共属性成为LoginServiceDelegate引用,因此LoginService不再需要导入ViewController。这样,ViewController依赖于LoginService,但LoginService不依赖于ViewController。
答案 1 :(得分:1)
要考虑两种模式:委托和阻止。阻止代码更快,我通常更喜欢委托网络操作。要使用块,请以这种方式编写登录服务:
// LoginService.h
- (void)login:(NSString *)username completion:(void (^)(NSDictionary *, NSError *))completion;
听起来你在这里使用NSURLConnection委托模式,所以我会假设。请注意,NSURLConnection还提供了一个很好的one-shot block method来执行请求。
// 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)是礼貌的,因此它不会保留调用上下文的任何部分。
答案 2 :(得分: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
在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{
}
希望这有帮助。