搞清楚OC的形参(NSMutableArray...等)
2018-08-18 本文已影响29人
ibingewin
搞清楚OC的形参(NSMutableArray...等)
前提:
近期在封装一个算法的时候,发现在方法中传递一个NSMutableArray类型的array,在方法中对其再赋值,等方法执行完之后,发现array并没有变化,导致出现问题,虽然当时很快的找到了解决方法,但原因到底是什么,明白的并不够彻底,现今有空,回头梳理一下
先回顾一下我的问题,代码如下:
- (void)test_passObject {
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:0];
[self pass:arr];
}
- (void)pass:(NSMutableArray *)arr {
arr = @[@"a"].mutableCopy;
}
我的本意是希望在[self pass:arr]之后能够得到一个新的arr,但实际结果却是这样
前:0x600000246510,(
)
后:0x600000246510,(
)
纳尼!居然没有变化!最直观的调试在pass方法中打印一下就清楚了:
- (void)test_passObject {
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:0];
NSLog(@"前:%p,%@", arr, arr);
[self pass:arr];
NSLog(@"后:%p,%@", arr, arr);
}
- (void)pass:(NSMutableArray *)arr {
arr = @[@"a"].mutableCopy;
NSLog(@"中:%p,%@", arr, arr);
}
输出为:
前:0x6000002584b0,(
)
中:0x60000025a8b0,(
a
)
后:0x6000002584b0,(
)
由此可见,在pass:方法中,传递的arr就像C中的int一样,只是一个值传递,对其的赋值并不会影响外部的实参,为了进一步证实这个观点,我又做了如下尝试:
- (void)test_passObject {
NSArray *arr = @[@1, @"1", @[@1], @[@1].mutableCopy, [UIView new]];
for (id obj in arr) {
NSLog(@"前:%p,%@", arr, arr);
[self pass:obj];
NSLog(@"后:%p,%@", arr, arr);
}
}
- (void)pass:(id)arr {
arr = @[@"a"].mutableCopy;
NSLog(@"中:%p,%@", arr, arr);
}
输出为:
------------------------------------------
前:0xb000000000000012,1
中:0x600000257400,(
a
)
后:0xb000000000000012,1
------------------------------------------
前:0x12641a088,1
中:0x600000257400,(
a
)
后:0x12641a088,1
------------------------------------------
前:0x604000016fc0,(
1
)
中:0x6000002578b0,(
a
)
后:0x604000016fc0,(
1
)
------------------------------------------
前:0x6040002502c0,(
1
)
中:0x6040002511c0,(
a
)
后:0x6040002502c0,(
1
)
-----------------------------------------
前:0x7fc426619df0,<UIView: 0x7fc426619df0; frame = (0 0; 0 0); layer = <CALayer: 0x604000223ba0>>
中:0x600000253590,(
a
)
后:0x7fc426619df0,<UIView: 0x7fc426619df0; frame = (0 0; 0 0); layer = <CALayer: 0x604000223ba0>>
可以很清楚的看到:前、后的输出完全一样,中的任何变化,都对后都没有影响,甚至传值为nil也一样。
由此可以得出概论:OC方法中的形参与C函数的形参一样,全都是值传递。对于OC对象而言,其本质是void *指针,所以也就是指针值传递。在方法中,传递的形参就是一个新的指针变量,只是接收了传过来的指针值,之后对其的任何赋值操作,只是修改该指针变量的指向而已,完全不会影响到外部对象。
所以要实现我一开始的初衷:在方法中修改NSMutableArray,方法有两种:
- 传值
NSMutableArray **:用指针的指针就可以进行赋值操作,就好比C中的int,其实系统就有很多这样的操作,例如常用的NSError,都是传值&error,这样才能在内部处理错误后,返回上来; - 不要用
=赋值,只用OC的方法调用:如添加元素就用addObject:,移除就removeObject:
PS: 第二种只适用于可变类型的对象,建议使用第一种方法。其实这都是刚开始学OC时应该清楚的,但当时不知道为什么,了解的不够清楚,导致现在又要回头补习😂,哎!基本功一定要扎实,不然总有让你后悔的时候!