Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Cannot set the result on a completed task." even with trySetResult #207

Closed
driver733 opened this issue Dec 26, 2015 · 8 comments
Closed
Assignees

Comments

@driver733
Copy link

When this method is used for the second time (for the same instance), I get an exception, even though "mainTask" does get a new reference when this method is used again.

func didFinishVKAuthentication() -> BFTask {
    var mainTask = BFTaskCompletionSource()
    // auth with vk
    PFUser.logInWithUsernameInBackground(username, password: "").continueWithBlock({
      (task: BFTask!) -> AnyObject! in
      if task.error == nil {
        mainTask.setResult(nil) // trySetResult also raises an exception
      } else {
        // process error
      }
      return nil
    })
  } 
    return mainTask.task
  }

Here`s the stack trace.

2015-12-26 01:53:14.265 Moviethete[2202:1737693] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot set the result on a completed task.'
*** First throw call stack:
(
    0   CoreFoundation                      0x03c30746 __exceptionPreprocess + 182
    1   libobjc.A.dylib                     0x04007a97 objc_exception_throw + 44
    2   CoreFoundation                      0x03c3066d +[NSException raise:format:] + 141
    3   Bolts                               0x008f8e0d -[BFTaskCompletionSource setResult:] + 205
    4   Moviethete                          0x001385df _TFFFC10Moviethete13UserSingelton18loginWithVkontakteFS0_FT_CSo6BFTaskU_FTS0_CSo14NSNotification_T_U_FTS0_S2__T_ + 303
    5   Moviethete                          0x0012f757 _TPA__TFFFC10Moviethete13UserSingelton18loginWithVkontakteFS0_FT_CSo6BFTaskU_FTS0_CSo14NSNotification_T_U_FTS0_S2__T_ + 103
    6   Moviethete                          0x00174a59 _TFFE10MovietheteCSo20NSNotificationCenter11addObserveruRq_Ss9AnyObject_FS0_FTq_4nameGSqSS_6objectGSqPS1___5queueGSqCSo16NSOperationQueue_7handlerFT8observerq_12notificationCSo14NSNotification_T__PS1__U_FS3_T_ + 105
    7   Moviethete                          0x001734a2 _TPA__TFFE10MovietheteCSo20NSNotificationCenter11addObserveruRq_Ss9AnyObject_FS0_FTq_4nameGSqSS_6objectGSqPS1___5queueGSqCSo16NSOperationQueue_7handlerFT8observerq_12notificationCSo14NSNotification_T__PS1__U_FS3_T_ + 114
    8   Moviethete                          0x00174ad4 _TTRXFo_oCSo14NSNotification_dT__XFdCb_dS__dT__ + 68
    9   Foundation                          0x012e7fef -[__NSObserver _doit:] + 314
    10  Foundation                          0x012e7ea0 __67-[NSNotificationCenter addObserverForName:object:queue:usingBlock:]_block_invoke + 49
    11  CoreFoundation                      0x03bfabe4 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    12  CoreFoundation                      0x03bfabc0 ___CFXNotificationPost_block_invoke + 80
    13  Foundation                          0x013c6855 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    14  Foundation                          0x012ee5a5 -[NSBlockOperation main] + 99
    15  Foundation                          0x012cdab7 -[__NSOperationInternal _start:] + 700
    16  Foundation                          0x012cd7e9 -[NSOperation start] + 83
    17  Foundation                          0x012cd633 __NSOQSchedule_f + 237
    18  libdispatch.dylib                   0x048c3bef _dispatch_client_callout + 14
    19  libdispatch.dylib                   0x048a96bb _dispatch_main_queue_callback_4CF + 993
    20  CoreFoundation                      0x03b898ee __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
    21  CoreFoundation                      0x03b475f0 __CFRunLoopRun + 2256
    22  CoreFoundation                      0x03b46a5b CFRunLoopRunSpecific + 443
    23  CoreFoundation                      0x03b4688b CFRunLoopRunInMode + 123
    24  GraphicsServices                    0x06ea22c9 GSEventRunModal + 192
    25  GraphicsServices                    0x06ea2106 GSEventRun + 104
    26  UIKit                               0x026d30b6 UIApplicationMain + 1526
    27  Moviethete                          0x000a716c main + 140
    28  libdyld.dylib                       0x048eeac9 start + 1
    29  ???                                 0x00000001 0x0 + 1
)
@driver733
Copy link
Author

I have tried calling mainTask.setResult(nil) on the main thread and everything worked fine...
Could someone provide an explanation? Is it indeed typical to get such error when the stack is too deep?
p.s. trySetResult also raises an exception

@nlutsenko
Copy link
Member

This should actually not produce an error, unless you are trying to set the result on a mainTaskCompletionSource twice. It's super strange that you are seeing this here, is there any chance that you set it twice, say in any other place? There is also trySetResult() - which ignores the fact that the result is already set.

Also, from the stack trace above - it looks like it's throwing an exception from a different stack frame:
Probably a block that is subscribed as an observer to NSNotificationCenter, something with the loginWithVkontakte method name, or inside that method...

It might be an Swift optimization problem as well, but I highly doubt it...

P.S. You can simplify your code to this:

func didFinishVKAuthentication() -> BFTask {
    // auth with vk
    return PFUser.logInWithUsernameInBackground(username, password: "").continueWithBlock { task: BFTask! -> AnyObject! in
        if task.faulted {
            return task
        }
        return nil
    }
}

@driver733
Copy link
Author

@nlutsenko Please see my updated comment. Sorry for miscommunication...

@nlutsenko
Copy link
Member

Sorry, getting confused, can you re-post a comment that was updated? Or combine the updates in a new comment? I can't seem to be able to find any changes between the previous one and the new one.

Also, I am 99% close to be certain that trySetResult() will not throw the exact same error, since exceptions are thrown only in case if trySetResult() returns false.

@driver733
Copy link
Author

@nlutsenko , The thing is that I still had an exception with task.trySetResult(), which is really strange. I was able to avoid raising the exception by running task.setResult() on the main thread. Could there be anything that I don`t understand or missing about working with NSNotifications and multithreading?

@nlutsenko
Copy link
Member

There is no possibility that the latest version of Bolts (1.5.1 or1.5.0) could throw an exception withtrySetResult` in this case, you might have been using an old version.
Also, if NSNotification is observed with a block and you are using a custom operation queue - there is no guarantee that the observed block is going to run on one thread, as well as multiple notification posts/observation registrations might have referenced the same task completion source and trying to set the result of it.

@iamroberthood
Copy link

Not sure why, but on Bolts(1.3.0) and Parse(1.9.0) I don't see the issue. When I update to Bolts(1.6.0) and Parse(1.12.0) it appears. I'm a newb, but wanted to post this incase it was helpful for anyone.

@driver733
Copy link
Author

My guess is that @nlutsenko is rights in his assumption that multiple notifications have called my completion block...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants