在Objective-C中调用2个方法时出现异步编程问题
A类内部:在Objective-C中调用2个方法时出现异步编程问题,objective-c,Objective C,A类内部: -(void)authenticateUser { authenticate_Obj = [classB_Obj authenticateMobileUser]; } Inside ClassB: -(AuthenticateObj*)authenticateMobileUser { [mobile_Obj AuthenticateMobileServer:self action:@selector(Handler:)]; return authenticate
-(void)authenticateUser
{
authenticate_Obj = [classB_Obj authenticateMobileUser];
}
Inside ClassB:
-(AuthenticateObj*)authenticateMobileUser
{
[mobile_Obj AuthenticateMobileServer:self action:@selector(Handler:)];
return authenticate_G_Obj;
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
}
现在,一旦classB的authenticateMobileUser方法将控件返回给ClassA,我们将启动对象authenticate_Obj
我的问题是,当我运行项目时,authenticate_Obj为空。。。实际上,当它进入handler方法时,对象被初始化。但是被控制的返回到ClassA,而不进入Handler方法。我想这就是异步执行的问题。
如何使其进入handler方法,然后只将控件返回给ClassA
请帮帮我
谢谢。我想您是说AuthenticateMobileServer:action:是异步的,您希望阻止它,直到它完成,以便您可以获取返回值。不幸的是,在不知道它是如何工作的情况下,我们无法真正告诉您。主要问题是它是在主线程上运行处理程序操作还是在辅助线程上运行处理程序操作 如果它在主线程上运行操作,最好的策略是立即从authenticateMobileUser返回,而不等待身份验证对象,并禁用依赖于身份验证的UI元素。然后,当您稍后获得身份验证对象时,应该重新启用UI元素 如果它在后台线程上运行该操作,最简单的方法是设置另一个类似于Handler的方法。顺便说一下,方法和变量的命名约定是以小写开头,然后使用performSelectorOnMainThread:waitUntilDone:从Handler调用。然后,您可以使用与上述相同的策略。听起来您想做的是阻止执行,直到身份验证完成。如果AuthenticateMobileServer生成一个后台线程在其中工作,这可能是可能的-您可以使用一个同步对象,例如-但这确实是一个坏主意。如果要阻止,为什么还要有一个背景线程呢?线程同步是出了名的棘手,如果你不知道自己在做什么,那么很容易出错,让我们面对现实吧,你不知道 相反,您可能应该接受在进行身份验证时会有一段时间的不确定性,在此期间,您的应用程序应保持在某种中间状态进行处理,然后使用回调在身份验证完成时通知您,然后您可以继续对经过身份验证的用户执行任何需要执行的操作 有很多方法可以做到这一点,但问题中没有足够的细节来说明哪种方法最好。但是您似乎已经在ClassB中使用了非常类似的东西,所以我要说,在ClassA中也要这样做:
显然,这只是一个草图,不打算按原样使用。您需要考虑在等待状态下应用程序中的内容,其中身份验证在进行中,而身份验证对象OBR仍然是NIL。但希望你能明白这个想法。JeremyP和walkytalky的两个答案都是正确的,都是创建响应式用户界面的核心。经验法则: 如果您在主线程上执行潜在的阻塞操作(如联网),您将遇到麻烦 至少有两个原因: 您正在阻止运行循环,因此它无法再处理用户事件。这将导致mac上出现旋转的海滩球,mac和iOS上出现无响应的UI。 如果您使用的是iOS,则会有一个看门狗四处查看您的UI是否仍在响应用户事件。如果您阻塞UI的时间超过我认为的20秒,您将被终止,错误代码为0x8badf00d。 所以要完成这些事情,可能需要一些时间,你必须在后台线程上完成。正如JeremyP和walkytalky的两个答案所指出的,你经常会收到一个回调。这很好,但总共有三种消息传递方式: 代表团 通知 Kev值观测 这三种方法都可以使用。它们之间有细微的差别。其中最重要的一个是委派是1:1消息传递,而另一个to是1:n消息传递 既然如此,就不要认为必须使用NSThread。请查看NSOperation和NSOperationQueue。它们允许在操作中封装工作片段,并允许它们在后台的队列上运行。另外,如果您使用@selectormethodname:语法使用这些回调,则会出现一些新的内容:块。通常有一些等效的方法将块而不是选择器作为回调执行 在这里结束是一条黄金法则: 您可以在后台线程上更新模型,但决不能在后台线程上更新UI
查看有关这些主题的WWDC10视频。有一个关于网络的两个部分的演讲,详细解释了这些概念。我认为你的课程缺少一些重要的部分。使用动作:@selectorHandler:语法对我来说似乎很难。如何制作冰毒
@selector run 1st然后AuthenticateMobileServer中的od??如果您非常困难,我建议您停止正在做的事情,阅读一本关于Objective-C或C编程的好书或教程。
Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = nil;
[classB_Obj authenticateMobileUserAndNotify:self action:@selector(authenticatedObject:)];
// returns more or less immediately, not yet authenticated
}
-(void)authenticatedObject:(YourAuthObjectClass*) authObj
{
authenticate_Obj = authObj;
// do post-authentication stuff here
}
Inside ClassB:
-(void)authenticateMobileUserAndNotify:(id)target action:(SEL)sel
{
// I'm making these ivars for simplicity, there might be other considerations though
callbackTarget = target;
callbackSelector = sel;
[mobile_Obj AuthenticateMobileServer:self action:@selector(Handler:)];
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
[callbackTarget performSelectorOnMainThread:callbackSelector withObject:authenticate_G_Obj waitUntilDone:NO];
}