有一些原本我們認為很基礎的,而且很理所當然的,在實踐之后才發現,麻蛋原來是這樣
回顧一下c語言的參數傳遞
C語言中的參數傳遞
1、傳值方式
原理:形參和實參占不同內存單元,傳遞的實際上是實參變量或表達式的一個拷貝副本,將這個副本值傳給形參,形參內存單元內容保存的正是這個副本值,相當于給形參進行初始化,形參的值發生變化也不會傳回給實參,因此是單向傳遞。
例如:
void increase(int x)
{
x++;
}
當在主函數中調用上面這個函數時,會在ncrease函數內存棧中為形參x分配一個內存單元,然后把實參的值傳到這個內存單元中,相當于給形參初初化了,然后形參x自增1,它改變的僅僅是形參內存單元中的內容,而實參內存單元中的內容并沒有改變。當被調用函數執行完畢后,形參所分配的內存單元也被收回。
2、傳地址方式
原理:和傳值方式一樣,當調用函數時也要為形參分配內存,被調函數執行完畢后也要收回內存。不同的是傳遞的是實參變量地址的拷貝值,而不是實參變量的值,在被調函數中對地址所指對象的操作會改變實參的值。但是形參的內容即存放的實參變量地址并不會改變。
** OC中傳遞對象就是用這種方式呀,但是并沒有被改變 我很疑惑**
例如:
void increase(int * x)
{
(*x)++;
}
int main()
{
int i,*x;
i=10;
*x=20;
increase(&i);//如果定義的不是指針變量,那變要加上個取址號&,當然如果形參實參是數組的話,直接用數組名即可,因為數組名本身代表的就是數組的首地址
increase(x);
}
主函數調用被調函數后,主函數中的i和*x的值都會改變。
OC參數傳遞
NSString
先看看測試的代碼
- (void)viewDidLoad {
[super viewDidLoad];
NSString *str = @"viewDidLoad";
NSLog(@"viewDidLoad 改變前:%@",str);
[self changNSString:str];
NSLog(@"viewDidLoad 改變后:%@",str);
}
- (void)changNSString:(NSString *)str {
NSLog(@"changNSString 改變前:%@",str);
str = @"changNSString";
NSLog(@"changNSString 改變后:%@",str);
}
大家覺得NSLog(@"viewDidLoad 改變后:%@",str);會打印什么.
** 可以改變str的值么**
經過測試,** str ** 經過函數changNSString的修改后根本沒有改變
**2016-04-01 18:01:06.762 CommentDemo[8807:186874] viewDidLoad ****改變前****:viewDidLoad**
**2016-04-01 18:01:06.762 CommentDemo[8807:186874] changNSString ****改變前****:viewDidLoad**
**2016-04-01 18:01:06.762 CommentDemo[8807:186874] changNSString ****改變后****:changNSString**
**2016-04-01 18:01:06.762 CommentDemo[8807:186874] viewDidLoad ****改變后****:viewDidLoad**
這完全不符合常理呀!這是傳遞的地址呀.
NSMutableString
之后我換可變的字符串對象測試了一下:
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *mStr = [NSMutableString stringWithString:@"viewDidLoad"];
NSLog(@"viewDidLoad 改變前:%@",mStr);
[self changeMutableString:mStr];
NSLog(@"viewDidLoad 改變后:%@",mStr);
}
- (void)changeMutableString:(NSMutableString *)mStr {
NSLog(@"changNSMutableString 改變前:%@",mStr);
mStr = [NSMutableString stringWithString:@"changeMutableString"];
NSLog(@"changNSMutableString 改變后:%@",mStr);
}
測試結果
**2016-04-01 18:07:33.382 CommentDemo[8856:191232] viewDidLoad ****改變前****:viewDidLoad**
**2016-04-01 18:07:33.383 CommentDemo[8856:191232] changNSMutableString ****改變前****:viewDidLoad**
**2016-04-01 18:07:33.383 CommentDemo[8856:191232] changNSMutableString ****改變后****:changeMutableString**
**2016-04-01 18:07:33.383 CommentDemo[8856:191232] viewDidLoad ****改變后****:viewDidLoad**
** 同樣沒有改變 **
NSMutableArray
后來我換了可變的數組
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
for (NSString *str in mArray) {
NSLog(@"viewDidLoad 改變前 %@",str);
}
[self changeMutableArray:mArray];
for (NSString *str in mArray) {
NSLog(@"viewDidLoad 改變后 %@",str);
}
}
- (void)changeMutableArray:(NSMutableArray *)array {
[array addObject:@"3"];
for (NSString *str in array) {
NSLog(@"changeMutableArray %@",str);
}
}
測試結果
**2016-04-01 18:16:24.259 CommentDemo[8925:196443] viewDidLoad ****改變前**** 1**
**2016-04-01 18:16:24.259 CommentDemo[8925:196443] viewDidLoad ****改變前**** 2**
**2016-04-01 18:16:24.259 CommentDemo[8925:196443] changeMutableArray 1**
**2016-04-01 18:16:24.260 CommentDemo[8925:196443] changeMutableArray 2**
**2016-04-01 18:16:24.260 CommentDemo[8925:196443] changeMutableArray 3**
**2016-04-01 18:16:24.260 CommentDemo[8925:196443] viewDidLoad ****改變后**** 1**
**2016-04-01 18:16:24.260 CommentDemo[8925:196443] viewDidLoad ****改變后**** 2**
**2016-04-01 18:16:24.260 CommentDemo[8925:196443] viewDidLoad ****改變后**** 3**
** 值他媽的改變了 **
經過測試,可以知道在OC中,看似對象是聲明為指針類型(* Str),由于傳遞的時候我們沒有用取地址(&).結果根本沒有改變. 我開始懷疑傳遞的是不是地址了.是不是因為自始至終沒有用到過取地址符.
然后自己改為了如下方式,就能夠改變傳進來的值了
能夠改變傳遞的值
NSString正常改變
- (void)viewDidLoad {
[super viewDidLoad];
NSString *str = @"viewDidLoad";
NSLog(@"viewDidLoad 改變前:%@",str);
[self changNSString:&str];
NSLog(@"viewDidLoad 改變后:%@",str);
}
- (void)changNSString:(NSString **)str {
NSLog(@"changNSString 改變前:%@",*str);
*str = @"changNSString";
NSLog(@"changNSString 改變后:%@",*str);
}
測試結果
**2016-04-01 18:27:33.139 CommentDemo[8993:203983] viewDidLoad ****改變前****:viewDidLoad**
**2016-04-01 18:27:33.139 CommentDemo[8993:203983] changNSString ****改變前****:viewDidLoad**
**2016-04-01 18:27:33.139 CommentDemo[8993:203983] changNSString ****改變后****:changNSString**
**2016-04-01 18:27:33.139 CommentDemo[8993:203983] viewDidLoad ****改變后****:changNSString**
總結
看到這種狀況我能說服自己的就是:
NSString *str = @"viewDidLoad";
這樣的定義在OC中其實就是類似于c語言的普通變量而已,而不是指針變量.智商有點不夠用.
原因或許很簡單
看似和c語言地址傳遞一樣,同樣是*傳遞。但c語言拿到這個指針之后取了指針指向的內容并改變了內容。而oc中我們習慣直接str =?。讓這個指針指向了新的地方。并沒有改變函數外面原來指針指向的內容。這點特別重要,指針傳過來那個str本質是值傳遞,相當于copy了一份。所以在change函數里面的str并不是外面的str。哈哈。今天有點短路。
還是一點,c語言中改變了傳進來指針原來指向的內容,而oc中只改變了新指針指向的地方。
2016-4-11
談談自定義對象,給對象賦值又是怎樣的.
經過測試,給對象的屬性復制能夠在另一個函數改變其屬性
看看測試結果
**2016-04-11 14:19:47.708 CommentDemo[3027:130157] name: xiaomao, age: 17**
**2016-04-11 14:19:47.709 CommentDemo[3027:130157] name: newxiaomao, age: 89**
**2016-04-11 14:19:47.709 CommentDemo[3027:130157] name: newxiaomao, age: 89**
測試代碼
- (void)createCat {
Cat *cat = [Cat new];
cat.name = @"xiaomao";
cat.age = @"17";
NSLog(@"%@",cat);
[self catObjectTest:cat];
NSLog(@"%@",cat);
}
- (void)catObjectTest:(Cat *)cat {
cat.name = @"newxiaomao";
cat.age = @"89";
NSLog(@"%@",cat);
}
分析
當我在調用對象的屬性進行賦值的時候,其實是調用getter/setter方法,通過這樣的賦值,屬性值肯定改變呀.O(∩_∩)O~