为什么NSMutableArray必须用strong,而NSArray必须用copy?

本文详细解析了NSMutalbeArray与NSArray在Objective-C中的使用区别,包括不同修饰符(copy与strong)对数组的影响及如何正确设置属性以避免运行时错误。

1.NSMutableArray:

@property (nonatomic, copy) NSMutableArray *mArray;//等同于
- (void)setMArray:(NSMutableArray *)mArray {

_mArray = mArray.copy;

}

mArray属性就成了NSArrayNSMutableArray只能用strong修饰,不存在有copy修饰的情况,写了就成NSArray了。

如果是strong,直接是赋值_mArray = mArray;右边是什么,左边就是什么,并且是强引用新值。这样就和strong的作用一样了。

所以:用copy为关键字的话,调用setter方法后。是对赋值对象进行深拷贝。并且拷贝的对象是copy的(不可变的),而不是

mutableCopy的(可变的)。所以用copy修饰的mutableArray也被视为Array了,所以再用mutableArray的方法就会发生崩溃。

2.NSArray

strong修饰之后,由于只是强引用,所以副本对象数组和源对象数组只是指向同一个内存区域,这样就会造成副本对象数组会随着

源对象数组的改变而改变,即便有时候你并不想让副本对象跟着改变。



@property (nonatomic, strong) NSArray *array;
NSMutableArray *mutableArray = [NSMutableArray array];  

 [mutableArray addObject:@"1"];  
 self.array = [NSArray array];  
 self.array = mutableArray;   
 NSLog(@"array---%@", self.array);  

 [mutableArray addObject:@"2"];  
 NSLog(@"array---%@", self.array);

打印结果显示,array的长度发生了变化,具有调用mutableArray方法的能力。

结论:当修饰可变类型的属性时,如NSMutableArrayNSMutableDictionaryNSMutableStringstrong当修饰不可变类型的属性时,如

NSArrayNSDictionaryNSString,用copy


#import <UIKit/UIKit.h> #import <ReactiveObjC/ReactiveObjC.h> NS_ASSUME_NONNULL_BEGIN #pragma mark - Model @interface StoryScene : NSObject @property (nonatomic, copy) NSString *sceneTitle; @property (nonatomic, copy) NSString *visualDescription; @property (nonatomic, strong) NSArray<NSString *> *symbolicElements; @end @implementation StoryScene @end @interface DigitalTool : NSObject @property (nonatomic, copy) NSString *toolName; @property (nonatomic, copy) NSString *usageDescription; @property (nonatomic, strong) NSArray<NSString *> *appliedScenes; @end @implementation DigitalTool @end @interface InteractionPlan : NSObject @property (nonatomic, copy) NSString *platform; @property (nonatomic, strong) NSArray<NSString *> *engagementMethods; @end @implementation InteractionPlan @end #pragma mark - ViewModel @interface StoryViewModel : NSObject @property (nonatomic, strong) NSArray<StoryScene *> *scenes; @property (nonatomic, strong) RACCommand *loadScenesCommand; @end @implementation StoryViewModel - (instancetype)init { self = [super init]; if (self) { @weakify(self); _loadScenesCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id _) { @strongify(self); return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [self fetchScenesFromService]; [subscriber sendCompleted]; return nil; }]; }]; } return self; } - (void)fetchScenesFromService { StoryScene *scene1 = [StoryScene new]; scene1.sceneTitle = @"黑暗中的微光"; scene1.visualDescription = @"黑白基调牢房,霉变米饭特写"; StoryScene *scene2 = [StoryScene new]; scene2.sceneTitle = @"铁窗下的课堂"; scene2.symbolicElements = @[@"树枝笔", @"棉灰墨", @"半截铅笔"]; _scenes = @[scene1, scene2]; } @end @interface ToolViewModel : NSObject @property (nonatomic, strong) NSArray<DigitalTool *> *tools; @property (nonatomic, strong) RACSubject *toolSelectedSubject; @end @implementation ToolViewModel - (instancetype)init { self = [super init]; if (self) { _toolSelectedSubject = [RACSubject subject]; [self setupTools]; } return self; } - (void)setupTools { DigitalTool *tool1 = [DigitalTool new]; tool1.toolName = @"PikaLabs"; tool1.usageDescription = @"水墨晕染风格动画"; DigitalTool *tool2 = [DigitalTool new]; tool2.toolName = @"Runway Gen-3"; tool2.usageDescription = @"动态分镜特效"; _tools = @[tool1, tool2]; } @end #pragma mark - View @interface SceneCell : UICollectionViewCell @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UIImageView *symbolImageView; - (void)configureWithScene:(StoryScene *)scene; @end @implementation SceneCell - (void)configureWithScene:(StoryScene *)scene { _titleLabel.text = scene.sceneTitle; _symbolImageView.image = [UIImage imageNamed:scene.symbolicElements.firstObject]; } @end @interface MainViewController : UIViewController @property (nonatomic, strong) StoryViewModel *storyVM; @property (nonatomic, strong) ToolViewModel *toolVM; @property (nonatomic, strong) UICollectionView *collectionView; @end @implementation MainViewController - (void)viewDidLoad { [super viewDidLoad]; [self setupCollectionView]; [self bindViewModels]; } - (void)setupCollectionView { UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; _collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; [_collectionView registerClass:SceneCell.class forCellWithReuseIdentifier:@"SceneCell"]; [self.view addSubview:_collectionView]; } - (void)bindViewModels { @weakify(self); [[_storyVM.loadScenesCommand execute:nil] subscribeCompleted:^{ @strongify(self); [self.collectionView reloadData]; }]; [_toolVM.toolSelectedSubject subscribeNext:^(DigitalTool *tool) { NSLog(@"Selected tool: %@", tool.toolName); }]; } #pragma mark - UICollectionViewDataSource - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return _storyVM.scenes.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { SceneCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"SceneCell" forIndexPath:indexPath]; [cell configureWithScene:_storyVM.scenes[indexPath.item]]; return cell; } @end #pragma mark - Coordinator @interface AppCoordinator : NSObject @property (nonatomic, strong) UINavigationController *navigationController; - (void)start; @end @implementation AppCoordinator - (void)start { MainViewController *mainVC = [MainViewController new]; mainVC.storyVM = [StoryViewModel new]; mainVC.toolVM = [ToolViewModel new]; _navigationController = [[UINavigationController alloc] initWithRootViewController:mainVC]; } @end #pragma mark - AppDelegate @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic, strong) UIWindow *window; @property (nonatomic, strong) AppCoordinator *coordinator; @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { _window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; _coordinator = [AppCoordinator new]; [_coordinator start]; _window.rootViewController = _coordinator.navigationController; [_window makeKeyAndVisible]; return YES; } @end NS_ASSUME_NONNULL_END
最新发布
08-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值