CXCallObserver fires delegate method every time applicationDidBecomeActive is called? - ios

So I want to get the timings of the cellular call that I place from my app. I get call's start time as soon as call gets connected, but i also get start time block executed when calls ends which overwrites my callStartTime property. Same thing happens with incoming calls as well (as you can see from the console log screenshot attached). I am using telprompt:// to place calls and return back to app. Is this a bug?

The CXCallObserver delegate method is invoked whenever calls changed, and is invoked once when a call connects and then later if/when that call ends. The hasConnected and hasEnded properties should be interpreted as "has ever connected" and "has ever ended", respectively.
Thus, I recommend using logic such as this:
if (call.hasConnected) {
if (!call.hasEnded) {
// record start time (unless start time has already been recorded)
} else {
// record end time (unless end time has already been recorded)
}
}

Related

What happens if the `NEPacketTunnelflow` method `readPacketsWithCompletionHandler` is called multiple times?

When calling the method
- (void)readPacketsWithCompletionHandler:(void (^)(
NSArray<NSData *> *packets, NSArray<NSNumber *> *protocols))completionHandler;
the completionHandler is either called directly, in case packets are available at call time, or it is called at a later tim when packets become available.
Yet what is nowhere documented is: What happens if I call this method again before the prior set completionHandler has ever been called?
Will the new handler replace the prior set one and the prior set one won't get called at all anymore?
Are both handler scheduled and called as data arrives? And if so, will they be called in the order I passed them, in reverse order, or in random order?
Has anyone any insights on how that method is implemented?
Of course, I can make a demo project, create a test setup, and see what results I get through testing but that is very time consuming and not necessarily reliable. The problem with unspecified behavior is that it may change at will without letting anyone know. This method may behave differently on macOS and iOS, it may behave differently with every new OS release, or depending on the day of the week.
Or does the fact that nothing is documented is by intention? Do I have to interpret that as: You may call this method once and after your callback was executed, you may call it again with the same or a new callback. Everything else is undefined behavior and you cannot and should not rely on any specific behavior if use that API in a different manner.
As nobody has replied so far, I tried my best to figure it out myself. As testing is not good enough for me, here is what I did:
First I extracted the NetworkExtension framework binary from the dyld cache of macOS Big Sur using this utility.
Then I ran otool -Vt over the resulting binary file to get a disassembler dump of the binary.
My assembly skills are a bit rusty but from what I see the completionHandler is stored in a property named packetHandler, replacing any previous stored value there. Also a callback is created in that method and stored on an object obtained by calling the method interface.
When looking at the code of this created callback, it obtains the value of the packetHandler property and sets it to NULL after the value was obtained. Then it creates NSData and NSNumber objects, adds those to NSArray objects and calls the obtained handler with those arrays.
So it seems that calling the method again just replaces the previous completionHandler which is never be called in that case. So you must not rely that a scheduled handler will eventually be called at some time in the future if the tunnel is not teared down if the possibility exists that your code might replace it. Also calling the method multiple times to schedule multiple callbacks has no effect as as only the last one will be kept and eventually be called.

Does URLSession.dataTask(with:completionHandler:) always call completionHandler only once?

After I create a new session data task with URLSession.dataTask(with:completionHandler:) and start the task by calling its resume() method, given that the app doesn't crash while the request is running, is it safe for me to assume that completionHandler (passed to URLSession.dataTask(with:completionHandler:) above) will always eventually get called only once, even if something weird happens with the network request (like if the connection drops) or with the app (like if it goes into the background)?
Note: I'm not explicitly calling cancel() or suspend() on the task. Just resume().
I want to know the answer to this question because (from my app's main thread) I'm creating and starting (one after the other) multiple asynchronous network requests and want to know when the last one has finished.
Specifically, I'm working on an app that has a custom class called Account. On launch, the app (assuming it finds an account access token stored in UserDefaults) creates only one instance of that class and stores it to a global variable (across the entire app) called account, which represents the app's currently-logged-in account.
I've added a stored var (instance) property to Account called pendingGetFooRequestCount (for example) and set it to 0 by default. Every time I make a call to Account.getFoo() (an instance method), I add 1 to pendingGetFooRequestCount (right before calling resume()). Inside completionHandler (passed to URLSession.dataTask(with:completionHandler:) and (to be safe) inside a closure passed to DispatchQueue.main.async(), I first subtract 1 from pendingGetFooRequestCount and then check if pendingGetFooRequestCount is equal to 0. If so, I know the last get-foo request has finished, and I can call another method to continue the flow.
How's my logic? Will this work as expected? Should I be doing this another way? Also, do I even need to decrement pendingGetFooRequestCount on the main thread?
URLRequest has a timeoutInterval property, its default value is 60 seconds. If there is no response by then, the completion is called with non-nil error.

What comes first applicationWillResignActive app delegate method or the Notification for the same event?

In my app delegate I save(persist) an object when the applicationWillResignActive: method is called. I have a view controller which responds to UIApplicationWillResignActiveNotification and makes a modification to the previously mentioned object but doesn't save(persist) the object itself.
What I need to know is if that change will be persisted trough the applicationWillResignActive: method or if I should explicitly save it in the view controller just to be sure?
Edit: NSLog test result is: 1st is the delegate method, 2nd it is the Notification method.
I wasn't sure the test would guarantee me that the order will be the same every time because I don't know how notification center works. That is why I posted the question before testing and giving results.
The documentation for applicationWillResignActive: says, "After calling this method, the app also posts a UIApplicationWillResignActiveNotification notification to give interested objects a chance to respond to the transition."
The "after" makes me believe that you will not get the changed value inside applicationWillResignActive:.
Of course, inserting a couple of NSLog lines would let you prove the order of operation for yourself.

CNContactStoreDidChangeNotification multiple times [duplicate]

I am able to observe the CNContactStoreDidChangeNotification when the contact database is changed while the app is in background state. I am pretty sure that only one observer was added to NSNotificationCenter.
The problem is NSNotificationCenter posts MULTIPLE times (2, 3, 5, and even more times) even if I only add one new contact.
Where is the problem?
Make certain you aren't adding the observer multiple times. This can happen without you realizing it if (for example) you call -addObserver from -viewDidLoad or -viewDidAppear in your view controller (as these might get called more than once throughout the life of your application), or from any of the application state callbacks in your app delegate (-applicationDidBecomeActive, -applicationWillResignActive, -applicationDidEnterBackground, -applicationWillEnterForeground, etc).
Wrap the call to -addObserver in a conditional that ensures it can only be called once (set a flag), and put NSLog statements around it so you can see in the debug console if you are getting there more than once. Search your code for other calls to -addObserver that you might have forgotten about.
Call -removeObserver before adding it, just to be sure (making sure to pass the same name and object as when you added it). Calling -removeObserver on an observer that doesn't exist is okay. Note that this is more of a band-aid than a fix - your code should be smart enough to know whether or not you've already added it - but this might help you diagnose the problem).
I just wrote a quick minimal test program that adds an observer (once!) on CNContactStoreDidChangeNotification and I only get the notification once when I add or change a contact. Write a similar test program for yourself and see if you get the same result. If your test program works correctly, then it is likely that your app is doing something you don't expect (and calling -addObserver multiple times).
I had the same problem, the number of times it fired varied between 2 & 3. The solution that worked for me was to set a semaphore variable, set in the handler and reset the semaphore when finished. Wrap the address book processing in an if statement on the semaphore to ignore further calls.
addressBkSemphore is reset to false in buildFrendsAndContacts
- (void)addressBkChange:(NSNotification *)note
{
if (addressBkSemphore == false)
{
addressBkSemphore = TRUE;
[self buildFrendsAndContacts];
}
}
Hope it helps.
You can start a one time execution timer or a dispatch after few seconds and cancel it in case there's a new contacts update within those seconds, thus ensuring that only the timer or dispatch_after triggered by the last update will actually execute (taking into account that all update calls come one after the other within under a sec. difference, as far as I tested)
And btw, I could reproduce the issue only when making change to contacts on the same device with my app. If I change the contacts on another device linked to the same apple account, there was only one update.

endturnwithnextparticipants, how does it work?

I am making a turnbased game for iOS with game center, 2 participants per match. I would like to implement a time limit on every turn, so that a player don't have to wait forever for the other player to finish its turn. I have tried:
currentMatch endTurnWithNextParticipants:[[NSArray alloc] initWithObjects:nextParticipant,nil] turnTimeout:GKTurnTimeoutDefault matchData:data completionHandler:^(NSError *error)
but nothing happens, the player still has forever to do their turn, so I am obviously missing something here.
What happens when the time limit is reached? How does gamecenter handle this, and where should I handle this?
That method updates the data stored on Game Center for the current match.
According to Apple Docs:
If the next player to act does not take their turn in the specified interval, the next player in the array receives a notification to act. This process continues until a player takes a turn or the last player in the list is notified.
When this method is called, it creates a new background task to handle the request. The method then returns control to your game. Later, when the task is complete, Game Kit calls your completion handler. Keep in mind that the completion handler may be called on a thread other than the one originally used to invoke the method. This means that the code in your block needs to be thread-safe.
I think you need to also end the players go on their end programatically.

Resources