2013年6月18日 星期二

彌月蛋糕試吃心得

因為女兒就快要出生,所以最近都在找適合的彌月蛋糕,去了家附近的幾家蛋糕店,每家店給我的印象都不太一樣。

第一家,xx鄉,以蜂蜜蛋糕出名,彌月禮盒很可愛,是我喜歡的包裝,不過跟店員說我們想試吃時,她隨手拿了個塑膠袋,裝了兩三塊餅乾就遞給我們,讓我們感覺很差,很像我們是來騙東西吃得。

第二家,xx屋,有專門設計的小禮盒裝試吃的小蛋糕,和幾塊餅乾,比前一家有進步,蛋糕不錯,列為考慮之一。

第三家,喜憨兒烘焙屋,店員非常的客氣,留下了我的聯絡方式,說會幫我預定試吃禮盒,幾天後可以過來拿,我心想不就現場給我就好了嘛,幹麼這麼麻煩,回家後我馬上收到她們的來信,提醒我哪一天去拿試吃禮盒。幾天過後,因為太忙的緣故,我比原訂日期晚了兩天才去,本以為應該沒有了,不過她們說還保留著,但不能給我,是要懲罰我忘了這件事情嗎??不是,是因為過了最佳品嚐時間,怕口感變了,影響我的感覺。昨天晚上,我終於拿到了喜憨兒烘焙屋的彌月試吃禮盒,一塊小蛋糕,三塊餅乾,這雖然不是我吃過最好吃的蛋糕,但我真的非常非常的喜歡,因為充滿了濃濃的尊重與祝福。




2013年6月4日 星期二

Objective-C Pointer

Objective-C中,呼叫方法時,參數的傳遞是 call by value,也就是複製一份值傳遞進去,網路上的有些資料提到類似 call by reference,其實骨子裡還是 call by value。而要解釋這個概念前不得不先解釋指標(Pointer)。

指標 Pointer

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSString * ptr = @"Content";
        NSLog(@"The value of ptr : %p",ptr);
        NSLog(@"The address of @\"Content\" : %p",@"Content");
        NSLog(@"The address of ptr : %p",&ptr);
    }
    return 0;
}

我們先來看這一行,NSString * ptr = @"Content"; ,這裡宣告了一個指標ptr,指向一個NSString的物件,而這個物件的值是@"Content",數值於電腦運算時,都存儲於記憶體中,可以想成一條馬路上有許多房子,大小固定,都有門牌,而物件有大有小,有些可能需要好幾間房子打通才放得下。示意圖如下,Ptr所存的值( 0x100001040 )剛好是這個字串的記憶體位置,ptr本身也有個Address是  0x7fff5fbff898。由這個例子可以知道要知道門牌位置必須使用 & 取址運算子,在NSLog中用%p列印出來。



那你也可能會問,ptr這個指標名稱又是存在哪裡了,應該也需要一塊記憶體去記錄吧!!沒錯,它在編譯執行後,作業系統記錄了它的名稱與Address,當你需要用ptr時,系統去找有沒有ptr這個東西,有的話又在記憶體的哪裡,這個你沒有辦法操作,也遠離了今天的主題,所以我們暫不討論。

&取址運算子,告訴我這個變數的記憶體位置。
*取值運算子,告訴我這個變數所指過去的物件值是什麼。

現在可以來看看方法參數的傳遞是如何運作的:

#import <Foundation/Foundation.h>

void someOperate(NSString *m);

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSString *o = @"Origin";
        NSLog(@"The address of o : %p",&o);
        NSLog(@"The value of o : %p",o);
        NSLog(@"The address of @\"Origin\" : %p",@"Origin");
        someOperate(o);
        NSLog(@"%@",o);
        NSLog(@"The address of o : %p",&o);
        NSLog(@"The value of 0 : %p",o);
    }
    return 0;
}

void someOperate(NSString *m)
{
    NSLog(@"**********");
    NSLog(@"The address of m : %p",&m);
    NSLog(@"The value of m :%p",m);
    m = @"Modify";
    NSLog(@"After");
    NSLog(@"The address of m : %p",&m);
    NSLog(@"The value of m :%p",m);
    NSLog(@"The address of @\"Modify\" : %p",@"Modify");
    NSLog(@"**********");
}



用一張圖來解釋發生什麼事情
當我們把o指標傳進方法後,複製了它的值給了m,而在方法中  m = @"Modify",又產生了一個物件NSString,m的值變成了@"Modify"的記憶體位置,所以不管我們在方法中怎麼改,原本的值不會有任何變化。

那如果我們想要的是直接更改原本的值,該怎麼做呢。有幾種方法,先講最容易的,把NSString改為NSMutableString,這樣在改值時,就會把原先的值,在原位置直接改變,而不是新產生一個新的物件。

#import <Foundation/Foundation.h> 

void someOperate(NSMutableString *m);

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSMutableString *o = [[NSMutableString alloc]initWithString:@"Origin"];
        NSLog(@"The address of o : %p",&o);
        NSLog(@"The value of o : %p",o);
        someOperate(o);
        NSLog(@"%@",o);
        NSLog(@"The address of o : %p",&o);
        NSLog(@"The value of 0 : %p",o);
    }
    return 0;
}

void someOperate(NSMutableString *m)
{
    NSLog(@"**********");
    NSLog(@"The address of m : %p",&m);
    NSLog(@"The value of m :%p",m);
    [m setString:@"Modify"];
    NSLog(@"After");
    NSLog(@"The address of m : %p",&m);
    NSLog(@"The value of m :%p",m);
    NSLog(@"**********");
}


但是如果沒有辦法更改為Mutable的類別時該怎麼辦,這時候有個迂迴的用法,指標的指標,既然無法更動指標所指的值,那就變動指標所存儲的記憶體Address,看一段代碼。

#import <Foundation/Foundation.h> 
void someOperate(NSString **m);

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        NSString *o = @"Origin";
        
        NSLog(@"The address of o : %p",&o);
        NSLog(@"The value of o : %p",o);
        NSLog(@"The address of @\"Origin\" : %p",@"Origin");
        
        someOperate(&o);
        
        NSLog(@"%@",o);
        NSLog(@"The address of o : %p",&o);
        NSLog(@"The value of o : %p",o);
    }
    return 0;
}

void someOperate(NSString **m)
{
    NSLog(@"**********");
    NSLog(@"The address of m : %p",&m);
    NSLog(@"The value of m :%p",m);
    NSLog(@"The value of *m : %p",*m);
    
    *m = @"Modify";
    
    NSLog(@"After");
    NSLog(@"The value of *m : %p",*m);
    NSLog(@"The address of m : %p",&m);
    NSLog(@"The value of m :%p",m);
    NSLog(@"The address of @\"Modify\" : %p",@"Modify");
    NSLog(@"**********");
}


這邊宣告一個變數o指向@"Origin",o的記憶體位置是f898,o的值是1048,也就是@"Origin"的記憶體位置,someOperate方法接受的參數為指標的指標,而也就是o指標的Address,傳入後,發現它複製了一份o指標,m所指的位置並不是o,接著把m所指向的值由1048改為1168 ( *m = @"Modify"),到目前為止都懂,奇妙的是原本o所存儲的值也跟著變了,藉由這個方式,可以在方法中修改原先傳入的指標的存儲值,使他指向新的物件。不過我疑惑的是,為什麼修改的是m所指向的值,o卻也跟著改變,這個我尚未明白,請高手指點明燈。