Task created in a session that has been invalidated
Asked Answered
D

1

6

I am getting the following crash on crashlytics which I can not reproduce on my device

Fatal Exception: NSGenericException
Task created in a session that has been invalidated

at the following line

NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromFile:filePathURL];
[task resume];
[self.session finishTasksAndInvalidate];

I handled session invalidation at the delegate method

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
    // Crashlytics logging
    [CrashlyticsKit setBoolValue:true forKey:@"URLSession_didBecomeInvalid"];
    self.session = [self createNewSession];
}

- (NSURLSession *)CreateSession {
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:SERVER_URL];

    if (@available(iOS 11.0, *)) {
        sessionConfig.waitsForConnectivity = YES;
    }
    return [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
}

after uploading a new build, I still have the same crash and no Crashlytics logs at "didBecomeInvalidWithError" at all!

any idea how to solve this crash?

Duke answered 11/3, 2020 at 12:43 Comment(6)
Is didBecomeInvalidWithError ever called? I guess what I'm trying to find out is: are you sure this method is implemented in some object that really is the URLSession delegate? — Also: are you conscious that a URLSession retains its delegate? This causes tricky memory management issues. What are you doing about that? — Also, please show createNewSession.Baptist
I have updated the questions and added more code. Note that the class is Singlton, i.e. the delegate exists over the application life cycle because I need to send files in multiple situations in background not only once.Duke
@Baptist when I debug the app the code reach didBecomeInvalidWithError when it finish uploading the files later it works again when trying to upload files but on production I got this crashDuke
So you are starting a task and invalidating the session (but hanging on to that old session reference for some reason)? And you are 100% sure that you never start another task on that session?Chivaree
@Chivaree So you mean that as soon as I use one session multiple times while the user is using the app (not just uploading one patch of files) then I should not invalidate it as there will be used for subsequent requests later in the time lineDuke
I’m saying that when you invalidate a session, you cannot ever use it again (and if you attempt to do so, you’ll get that error you describe). So, if you invalidate, nil your session reference so you won’t use it again. Alternatively, if you might ever need to use it again, just don’t invalidate it. Especially in the case of background sessions, IMHO.Chivaree
C
1

If you invalidate a session, you cannot ever use it again. If you attempt to use a previously invalidated session, you’ll get that error you shared with us.

That leaves you with two options:

  • If you must invalidate a session, I’d recommend setting your session reference to nil so you can’t accidentally use it again. If you have to do another request later, you would instantiate a new session object.

  • If you might ever need to use the session again, you can simply refrain from invalidating it. The memory impact of keeping a single session object around is largely inconsequential. It only really an issue if you’re creating many sessions.

Frankly, background sessions are complicated enough that I’d need a pretty compelling case for dealing with multiple ones (e.g. each with its own completion handler passed to my app delegate). I’d lean towards the single background session pattern if possible.

Chivaree answered 12/3, 2020 at 19:10 Comment(2)
Can there be a third option of handling (catching) that exception appropriately ?Bogard
@Bogard - No, you don't programmatically catch and handle exceptions, but rather excise them from your code entirely. (Swift formalizes this convention, not even offering easy ways to catch exceptions, only handling thrown errors, which despite the similarity in nomenclature, is a completely different concept.) As the Introduction to Exception Programming says, “You usually take care of these sorts of errors with exceptions when an application is being created rather than at runtime.”Chivaree

© 2022 - 2024 — McMap. All rights reserved.