iOS9中NSMutableArray调用removeAllObjects崩溃问题求助(Fabric捕获)
removeAllObjects Crash on NSMutableArray in iOS 9 Hey there, let's tackle this crash you're hitting with NSMutableArray's removeAllObjects method, especially on iOS 9. From your code and Fabric reports, here are the most likely causes and actionable fixes:
Common Root Causes
- Thread Safety Violations:
NSMutableArrayisn't thread-safe. Ifself.recommentGoodsArrayis being accessed/modified on a background thread while you callremoveAllObjectson the main thread, this can trigger a crash—older iOS versions like 9 have less strict runtime checks that let these race conditions slip through. - Accidental Immutable Assignment: If somewhere in your code (like
loadGoodsDetail) you assign anNSArraytoself.recommentGoodsArrayinstead of a mutable copy, callingremoveAllObjectson an immutable array will crash immediately. - Race Condition with Table View Reload: You're reloading the table view right after clearing the array. If the table view's data source methods are still executing (even partially) in the background, they might try to access the array mid-modification.
Step-by-Step Fixes
1. Enforce Thread Safety for Array Operations
Wrap all access to self.recommentGoodsArray in a synchronization block or use a serial queue to ensure only one operation runs at a time.
Option A: Synchronized Block (Quick Fix)
Modify your method to add a lock around the array operation:
- (void)clickColorWithIndex:(NSUInteger)index { // Lock the array to prevent concurrent access @synchronized(self.recommentGoodsArray) { [self.recommentGoodsArray removeAllObjects]; } // Always reload UI on the main thread dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); GoodsInfo *gInfo = [self.goodsInfo.relatedGoodsArray objectAtIndex:index]; // Fixed typo from `objectAt:` self.goods_id = gInfo.goods_id; [self loadGoodsDetail]; }
Option B: Serial Queue (Scalable for Frequent Operations)
For better performance with repeated array changes, create a dedicated serial queue:
// Add this property to your class interface @property (nonatomic, strong) dispatch_queue_t goodsArrayQueue; // Initialize it in viewDidLoad or your init method - (void)viewDidLoad { [super viewDidLoad]; self.goodsArrayQueue = dispatch_queue_create("com.yourapp.goodsArrayQueue", DISPATCH_QUEUE_SERIAL); } // Update your click handler - (void)clickColorWithIndex:(NSUInteger)index { dispatch_sync(self.goodsArrayQueue, ^{ [self.recommentGoodsArray removeAllObjects]; }); dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); GoodsInfo *gInfo = [self.goodsInfo.relatedGoodsArray objectAtIndex:index]; self.goods_id = gInfo.goods_id; [self loadGoodsDetail]; }
Make sure any other code that reads/writes self.recommentGoodsArray uses the same serial queue.
2. Verify Array Mutability Everywhere
Check every place you assign to self.recommentGoodsArray—ensure you're always using a mutable array. For example, when loading data:
// Wrong: Assigning an immutable array directly // self.recommentGoodsArray = fetchedGoodsArray; // Correct: Use mutableCopy to preserve mutability self.recommentGoodsArray = [fetchedGoodsArray mutableCopy];
3. Add Defensive Checks
Add quick guards to avoid invalid operations:
if (self.recommentGoodsArray && [self.recommentGoodsArray isKindOfClass:[NSMutableArray class]]) { @synchronized(self.recommentGoodsArray) { [self.recommentGoodsArray removeAllObjects]; } }
Bonus: iOS 9 Specific Edge Case
iOS 9 has quirks with NSMutableArray and KVO. If you're using KVO to observe this array, removeAllObjects can trigger unexpected notifications that lead to crashes. Temporarily remove observers before clearing the array, or ensure your KVO handlers are robust to empty arrays.
内容的提问来源于stack exchange,提问作者S.Dew

