對元素類型的要求
在 Objective-C 中,NSArray 只能存儲對象類型,而不能直接存儲基本類型(例如 int)。但是,可以將基本類型封裝在 NSNumber 等對象中,然后將這些對象存儲在 NSArray 中。這樣,enumerateObjectsUsingBlock: 方法中的 obj 仍然是指向這些對象的指針。
NSArray *array = @[@1, @2, @3];
[array enumerateObjectsUsingBlock:^(NSNumber *obj, NSUInteger idx, BOOL *stop) {int value = [obj intValue];NSLog(@"Object: %@, Int Value: %d, Address: %p", obj, value, obj);
}];
obj
是一個指針變量,局部變量
obj 和 array 中對應位置的元素指向相同的內存地址,但它們不是同一個指針變量,而是兩個指向同一對象的不同變量。
在 -enumerateObjectsUsingBlock: 方法中,塊枚舉會遍歷數組,并將每個元素的指針賦值給 obj。因此,obj 是一個局部變量,在每次迭代時指向數組中當前遍歷的元素。盡管它們指向同一對象,但 obj 是塊中的局部變量,而數組中的元素是數組中的存儲單元。
NSArray *array = @[@"one", @"two", @"three"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {NSLog(@"Object: %@, obj Address: %p, obj Pointer Address: %p, array[idx] Address: %p, array[idx] pointer Address: %p", obj, obj, &obj, array[idx], &array[idx]);
}];
循環引用問題
在 Objective-C 中使用 enumerateObjectsUsingBlock
時,同樣需要注意循環引用問題。enumerateObjectsUsingBlock
會將塊傳遞給枚舉方法,如果塊捕獲了對自身或外部對象的強引用,這可能導致循環引用,尤其是當這個對象也強引用調用該塊的對象時。
示例說明
假設有一個類 MyClass
,其實例方法使用 enumerateObjectsUsingBlock
:
@interface MyClass : NSObject
@property (nonatomic, strong) NSArray *array;
@end@implementation MyClass- (void)enumerateArray {[self.array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {// 這里使用了 selfNSLog(@"%@", self);}];
}@end
在上述代碼中,塊捕獲了 self
的強引用。如果 self
對象持有 array
,這就形成了一個循環引用,導致 self
無法被釋放。
解決方案
使用弱引用來打破循環引用,可以使用 __weak
或 __block
關鍵字:
@implementation MyClass- (void)enumerateArray {__weak typeof(self) weakSelf = self;[self.array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {// 這里使用了弱引用的 self__strong typeof(weakSelf) strongSelf = weakSelf;if (strongSelf) {NSLog(@"%@", strongSelf);}}];
}@end
在這個修改后的代碼中,使用 __weak
將 self
的弱引用傳遞到塊內,然后在塊內將其轉換為強引用以確保在使用過程中對象的生命周期被正確管理。