AVCaptureDeviceInput返回nil致部分用户相机功能崩溃求助
Hey there, let's break down the two main issues you're facing—crash in 10% of devices and deviceInputWithDevice returning nil for some users. Here's what I've debugged in similar cases and how to fix them:
deviceInputWithDevice Returns Nil (and How to Fix It) This is almost always tied to permissions, device availability, or unhandled errors. Let's cover each scenario:
Missing Camera Permissions
If the user hasn't granted camera access, or has denied/restricted it, creating a capture input will fail silently (or return nil). Always check permission status before initializing your capture session:AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (status == AVAuthorizationStatusDenied || status == AVAuthorizationStatusRestricted) { // Show an alert asking the user to enable camera access in Settings UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Camera Access Required" message:@"Please enable camera access in your device settings to use this feature." preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"Go to Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; }]]; [self presentViewController:alert animated:YES completion:nil]; return; } else if (status == AVAuthorizationStatusNotDetermined) { // Request permission first [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { if (granted) { // Initialize camera on the main thread dispatch_async(dispatch_get_main_queue(), ^{ [self setupCameraSession]; }); } else { // Handle denied permission } }]; return; }Device Already in Use
If another app (or even another part of your own app) is using the camera,deviceInputWithDevicewill return nil. Always capture the error to diagnose this:NSError *inputError = nil; AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&inputError]; if (!deviceInput) { NSLog(@"Failed to create capture input: %@", inputError.localizedDescription); // Show an alert telling the user to close other apps using the camera return; }Invalid Device or Preset
Rare, but some older devices might not supportAVCaptureSessionPresetPhoto, ordefaultDeviceWithMediaType:AVMediaTypeVideocould return nil (e.g., on devices without a camera, though these are rare now). Add checks:AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if (!device) { // Alert user their device doesn't support camera functionality return; } // Verify the session preset is supported if (![_session canSetSessionPreset:AVCaptureSessionPresetPhoto]) { _session.sessionPreset = AVCaptureSessionPresetHigh; // Fallback to a supported preset }
Looking at your code snippet, the most likely culprit is unlocked device configuration and potential thread safety issues:
Forgot to Unlock Device Configuration
You're callinglockForConfiguration:nil, but if the lock succeeds, you never callunlockForConfiguration! Leaving the device locked can cause race conditions, crashes, or failed operations later. Fix this immediately:if ([device lockForConfiguration:nil]) { if (device.autoFocusRangeRestrictionSupported) { device.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear; // Or your desired value } // Critical: Unlock the device after making changes [device unlockForConfiguration]; } else { NSLog(@"Failed to lock device configuration"); }AVCaptureSession Operations on Wrong Thread
All configuration and state changes forAVCaptureSession(like adding inputs/outputs, starting/stopping the session) must be done on a serial queue (or the main thread—serial queue is better for performance). If you're modifying the session from a background thread, this will cause crashes. Use a dedicated queue:// Declare a serial queue as an instance variable @property (nonatomic, strong) dispatch_queue_t cameraQueue; // Initialize it in your setup self.cameraQueue = dispatch_queue_create("com.yourapp.cameraQueue", DISPATCH_QUEUE_SERIAL); // Use it for all session operations dispatch_async(self.cameraQueue, ^{ [_session beginConfiguration]; // Add inputs/outputs, adjust presets, etc. [_session commitConfiguration]; [_session startRunning]; });Session Not Properly Retained
If_sessionis a weak reference, it might get deallocated unexpectedly, leading to crashes. Ensure it's a strong instance variable:@property (nonatomic, strong) AVCaptureSession *session;
- Always validate all objects (device, input, output) before using them—never assume they'll be non-nil.
- Test on older iOS versions (e.g., iOS 13/14) if you're supporting them, as some APIs behave differently.
- Check crash logs for specific stack traces—they'll point you to the exact line causing the crash (e.g., if it's a null pointer dereference or a thread violation).
内容的提问来源于stack exchange,提问作者Dipen Sekhsaria

