搞清楚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时应该清楚的,但当时不知道为什么,了解的不够清楚,导致现在又要回头补习😂,哎!基本功一定要扎实,不然总有让你后悔的时候!
网友评论