iOS SDK:如何在Objective-C中实现‘fire and forget’网络请求?
Hey there! Let's break down how to solve your problem: sending a request to your web service without caring about the response, while avoiding crashes if the app is closed or backgrounded before the response arrives.
Core Idea: Fire-and-Forget with Safe Callbacks
The key here is to create an asynchronous network request that doesn't hold strong references to objects that might be deallocated (like your view controller or app delegate) when the app's state changes. We'll use NSURLSession (Apple's recommended networking API) since it handles async operations natively—you don't need to spin up a separate background thread for this!
1. Basic Fire-and-Forget Request
This is the simplest approach: create a request, launch it with NSURLSession, and ignore the response entirely. The callback will run, but we'll make sure it doesn't reference any objects that could cause crashes.
// Step 1: Build your request NSURL *serviceURL = [NSURL URLWithString:@"https://your-webservice-endpoint.com/submit-data"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:serviceURL]; request.HTTPMethod = @"POST"; // Add your payload (example: JSON data) NSDictionary *dataToSend = @{ @"userID": @"12345", @"event": @"app_closed" }; NSError *jsonError; NSData *requestBody = [NSJSONSerialization dataWithJSONObject:dataToSend options:0 error:&jsonError]; if (!jsonError) { request.HTTPBody = requestBody; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; } // Step 2: Create session and fire the request NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // Do NOT reference self or any other objects here! // Optional: Log errors for debugging (no strong references) if (error) { NSLog(@"Fire-and-forget request failed: %@", error.localizedDescription); } }]; // Start the request [task resume];
Why this works:
- The
completionHandlerdoesn't hold any strong references to objects that might be deallocated (like your view controller). Even if the app is backgrounded or closed before the response comes back, the callback won't cause a crash because it doesn't try to access deallocated memory. NSURLSessionhandles the request asynchronously on a background queue—no need to manage your own threads.
2. Ensure Requests Complete in the Background (Optional)
If you need to guarantee the request finishes even if the user switches away from your app, use a background URL session. This lets the iOS system take over the request and complete it, even if your app is suspended.
// Step 1: Create a background session configuration (use a unique identifier) NSURLSessionConfiguration *backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.yourcompany.background-submission"]; NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfig delegate:nil delegateQueue:nil]; // Step 2: Build your request (same as the basic example) NSURL *serviceURL = [NSURL URLWithString:@"https://your-webservice-endpoint.com/submit-data"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:serviceURL]; // ... set HTTP method, body, headers ... // Step 3: Fire the request NSURLSessionDataTask *task = [backgroundSession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // Again, no references to self or other app objects here if (error) { NSLog(@"Background request failed: %@", error.localizedDescription); } }]; [task resume];
Notes on background sessions:
- Use a unique identifier for your background session—this helps the system reattach to the session if your app is terminated and restarted.
- The system will wake your app briefly when the request completes, but since our callback doesn't do anything critical, this won't cause issues.
Critical Crash Prevention Tips
- Never reference
self(or any other object) in the completion handler unless you use a weak reference. Since you don't care about the response, there's no need to access app state here anyway. - If you absolutely must include logic that references app objects (for debugging), use the weak-strong dance to avoid dangling pointers:
__weak typeof(self) weakSelf = self; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; // Exit if self is already deallocated // Safe to use strongSelf here if needed NSLog(@"Request completed for %@", strongSelf); }];
内容的提问来源于stack exchange,提问作者SolidSnake4444

