代码之家  ›  专栏  ›  技术社区  ›  suse

在Objective-C中调用2个方法时异步编程的问题

  •  -1
  • suse  · 技术社区  · 15 年前

    ClassA内部:

    -(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。

    我的问题是,当我运行项目时,authenticate对象为空…实际上,当它进入处理程序方法时,对象被初始化。但控件返回到ClassA,而不进入handler方法。我想这是异步执行的问题。 如何使它进入handler方法,然后只将control返回到classa??

    请帮助我。

    谢谢您。

    3 回复  |  直到 15 年前
        1
  •  2
  •   walkytalky    15 年前

    听起来像你 认为 您要做的是阻止执行,直到身份验证完成。这个 可以 可能的话 AuthenticateMobileServer 生成一个后台线程来工作——您将使用同步对象,例如 NSLock --但这真是个坏主意。如果无论如何都要阻止,为什么还要有一个后台线程呢?而线程同步是出了名的棘手,如果你不知道自己在做什么,那么很容易出错(让我们面对现实),而你不知道。

    相反,您可能应该接受在进行身份验证时会有一段不确定的时间,在此期间,您的应用程序应保持处理处于某种中间状态,然后使用 回调 当身份验证完成时通知您,然后您可以继续对已验证的用户执行所需的任何操作。

    有很多方法可以做到这一点,但问题中没有足够的细节来确切说明哪种方法最好。但你似乎已经在使用类似的东西 ClassB 所以我想说从 ClassA :

    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];
    }
    

    显然,这只是一个素描,并不打算按原样使用。在等待状态下,您需要考虑应用程序中发生了什么,正在进行身份验证,但是 authenticate_Obj 仍然 nil . 但希望你能理解。

        2
  •  0
  •   JeremyP    15 年前

    我想你是这么说的 AuthenticateMobileServer:action: 是异步的,您希望在完成之前阻止它,以便可以获取返回值。不幸的是,我们不能不知道它是如何工作的就告诉你。主要问题是它是在主线程还是在辅助线程上运行处理程序操作。

    如果它在主线程上运行操作,最好的策略是立即从 authenticateMobileUser 无需等待身份验证对象并禁用依赖于身份验证的UI元素。稍后,当您获得身份验证对象时,您应该重新启用UI元素。

    如果它在后台线程上运行该操作,最简单的方法是设置另一个类似于handler的方法(顺便说一下,方法和变量的命名约定是从小写开始),然后使用 performSelectorOnMainThread:waitUntilDone: . 然后您可以使用与上述相同的策略。

        3
  •  0
  •   GorillaPatch    15 年前

    Jeremyp和WalkTalky的答案都是正确的,它们是创建响应式用户界面的核心。经验法则:

    如果您在主线程上执行潜在的阻塞操作(如联网),则会遇到麻烦。

    至少有两个原因:

    1. 您正在阻塞运行循环,因此它无法再处理用户事件。这将导致Mac上的Beachball旋转,Mac和iOS上的UI无响应。
    2. 如果您在iOS上,会有一个看门狗四处走动,检查您的用户界面是否仍在响应用户事件。如果您阻塞UI的时间比我认为的20秒长,则将以错误代码0x8badf00d终止。

    所以要完成这些事情,可能需要一些时间,你必须在后台线程上完成。正如Jeremyp和WalkyTalky的两个答案所指出的,你经常会收到一个回调。这很好,但总共有三种信息传递方式:

    • 授权
    • 通知
    • kev值观测

    这三个都可以使用。他们之间有细微的差别。最重要的一点是,委派是1:1消息传递,而另一个是1:N消息传递。

    既然这样说了,就不要认为你必须用无头螺栓。查看nsOperation和nsOperationQueue。它们允许在操作中封装工作片段,并允许它们在后台的队列上运行。另外,如果将这些回调与@selector(methodname:)语法一起使用,则会有一些新的内容:blocks。通常有一些等价的方法将块而不是选择器作为回调执行。

    要完成这一点,有一条金科玉律:

    您可以在后台线程上更新您的模型,但决不能在后台线程上更新您的UI。

    查看有关这些主题的WWDC10视频。有一个关于网络的两部分很好的讨论,详细解释了这些概念。