With an iOS quick action (shortcut item), what is the purpose of the completion handler parameter?
Asked Answered
M

1

11

An iOS quick action / shortcut item is received by the app delegate's implementation of application(_:performActionFor:completionHandler:).

In that implementation, you are supposed to call the completionHandler. It takes a Bool.

Does anyone know what the Bool is for? I see no difference regardless of whether I pass true or false. (In fact, I see no difference even if I neglect to call the completionHandler!)

Maryrose answered 16/9, 2016 at 22:51 Comment(6)
Have you gone through the doc? application:performActionForShortcutItem:completionHandlerVirendra
@AdilSoomro Yes, I have. Have you?Maryrose
I could be wrong but I think your are responsible for the implementation of the method and also responsible to call such method conditionally, in which case you can pass a completionHandler (also your responsibility to implement), so in the implementation ofapplication(_:performActionFor:completionHandler:) you could pass a bool that can make sense to the logic that you implemented on the completionHandler and is up to the design of what you want to build.Oversight
@BlackSheep no, you don't write the completion handler, you just call it.Maryrose
This parameter is specific to let the system know if you quick action implementation succeeded, you need to call it after executing the required action's block of code. Some actions require asynchronous requests if one of the requests fail I am assuming the developer will not want to perform the selected action, thus he can call completionHandler(false)... otherwise, it's almost always called with a boolean value true.Blanchette
@Blanchette But the point is that I have tried passing true and I have tried passing false and I have tried not even calling the completion handler, and I see no difference whatever. We do perform the selected action, no matter what, and things do not look or behave differently. What I am asking you to do is show that I'm wrong somehow.Maryrose
T
7

Short answer: parameter is not used in implementation of block in iOS 10 (guess that in iOS 9 too, but can't check right now).

Long answer: let's see what happens inside of completion block:

___50-[UIApplication _handleApplicationShortcutAction:]_block_invoke:
push       rbp                               ; XREF=-[UIApplication _handleApplicationShortcutAction:]+132
mov        rbp, rsp
mov        rax, qword [ds:rdi+0x20]
mov        rdx, qword [ds:rdi+0x28]
mov        rsi, qword [ds:0x1179e88]         ; @selector(_updateSnapshotAndStateRestorationWithAction:)
mov        rdi, rax                          ; argument "instance" for method imp___got__objc_msgSend
pop        rbp
jmp        qword [ds:imp___got__objc_msgSend]
; endp

I run this on Intel64, so first argument should be stored in rdi register (when we calling block under ARC it is an instance of NSMallocBlock). There is no selector, so second parameter (bool argument) should be stored in rsi register. But rsi register is not used in code - it just sends message _updateSnapshotAndStateRestorationWithAction: to object ds:rdi+0x20 with argument ds:rdi+0x28.

Both ds:rdi+0x20 and ds:rdi+0x28 are captured pointers inside of the block.

Think that the guess with parameter as indicator for snapshot function was wrong.

Tussore answered 26/9, 2016 at 18:35 Comment(5)
This and your Catch UIViewAlertForUnsatisfiableConstraints in production answer are incredible. I would love to be able to reverse engineer UIKit like this.Tzong
I wonder how it would use this with the snapshot. It must have to do with the launch image. I'm guessing that if we return false, and we were suspended and now coming to the front, the runtime uses the snapshot it took at background time, because we are saying that we won't be changing our interface. But if we return true, maybe the runtime reverts to the original launch image. Something like that...? But if I understand you correctly, you're saying that in fact it doesn't make that decision after all.Maryrose
Yep, I think that your assumption is right and logical: if we are updating our UI, we need to update launch image and don't need otherwise. By default we use default launch image, because it is universal (it works like this in MobileSafari in iOS 9 Simulator). Exactly, it doesn't make that decision, because it doesn't use argument. However, I just tried not to call completion and nothing changes: I see default launch storyboard after opening app with shortcut item. Seems that the logic of snapshot updating occurs before calling appDelegate method.Tussore
@Maryrose unfortunately, I can't find exact place where it happens right now (I'll let you know, if I find it). One more idea - updating snapshot logic can be similar with application:performFetchWithCompletionHandler:, I will check it later.Tussore
@Maryrose My assumption about "preview" updating was partially correct: if we will receive background fetch notification, iOS resets launch image from snapshot to default. However, completion handler result is not affecting snapshot at all. So, I think that I was wrong about parameter as indicator of UI update need. Will update my answer, nothing else comes to mind.Tussore

© 2022 - 2024 — McMap. All rights reserved.