2012年7月29日 星期日

忘了密碼 - Single Mode for Lion

日前學員搬了一台Mac 問說,公司的電腦,之前用的人離職了,不知道密碼是什麼?怎麼辦?
在Unix環境之下,只要機器在手邊,忘了密碼通常會進入 Single Mode。在 Snow Leopard 或是 Lion 一開機的時候同時按著 Command + S 就會進入 Single Mode。
當 shell 跑完時,Snow leopard 輸入
mount -uw /
launchctl load /System/Library/LaunchDaemons/com.apple.DirectoryServices.plist
dscl . passwd /Users/<某個使用者> <新密碼>

就可以更改使用者的密碼

而在 Lion 的時候
mount -uw /
launchctl load /System/Library/LaunchDaemons/com.apple.opendirectoryd.plist

此時可以更改 root 密碼
接著輸入
dscl . passwd /Users/<某個使用者> <新密碼>

就可以更改某個使用者的密碼了
在這個時候會出現 com.apple.DirectoryServices.plist cannot be found 的錯誤
不用理會,重開機後就可以用新的密碼進入

2012年7月26日 星期四

Xcode 4.4 之旅 - LLVM 4.0

今天是 Mountain Lion 出閘的日子。 而對於開發者來說, Xcode 4.4 才是我們關注的焦點, 接下來讓麥克帶領大家, 來一場 Xcode 4.4 之旅。
首先要從 Mac App Store 下載 Xcode 4.4。 如圖。
安裝好之後,打開 Xcode, 先確定一下版本。為下圖。Version 4.4 (4F250)

二話不說先來開啟一個 Project 選 Master-Detail Application 如下圖
大致上和 4.3 沒什麼改變。眼尖的讀者應該會看到, 左邊 iOS 部分 cocos2d 的 Template
 Project 保留下來了。  因為 Template 資料夾在 ~/Library/Developer/Xcode/Templates/  而不在Xcode 執行的資料夾裡, 不會受到更新 Xcode 而影響。
選擇 Next 之後看到的視窗也和 4.3 差不多,如下,給個名字。 Hello4Table。
注意,這個 Project 的 Class Prefix 我是寫 GL。 選擇一個路徑之後按下 Create。 如下。
選擇 Project 設定 -> Build Setting 的搜尋欄填上 compiler 下方按鈕要選 all 。 如下圖就會看到主角出現了。 Apple LLVM  Compiler 4.0.
來看看 source coe 有什麼改變。 先看看 AppDelegate.h 和 AppDelegate.m 如下圖。
左邊的 .h 有 @property 右邊的 .m 卻沒有 @synthesize ? 聰明的大家猜到了吧, 是的。 在 Interface 的 property 不需要寫 synthesize 了, compiler 自動會幫大家補上。 《需要換 Xcode 4.4 理由加一》
再來把鏡頭轉到 GLMasterViewCotnroller.m 的 line 46 insertNewObject: 這個 method 身上。 如果沒看到 Line Number 可以在 Xcode Preference 的 Text Editor 打勾 如下

回到程式碼,看下方截圖。

紅色框起來的部分是 @[indexPath] 對照 4.3 寫的應該是 [NSArray arrayWithObject:indexPath]. 好的,究竟 @的作用是什麼呢?讓我們繼續看下去。
有看到之前文章 LLVM 新語法的朋友們,就會猜到了。@[@"one"] 指的就是 [NSArray arrayWithObject:@"one" ]。此文中還有提到 NSNumber 還有 NSDictionary 都可以用 @ 來改寫。這篇文章要做更深入的探討。首先來看

NSNumber 

Integer 


NSNumber * intNum = [NSNumber numberWithInt:10];
     intNum = @10; 
 

Float


NSNumber * floatNum = [NSNumber numberWithFloat:100.5];
      floatNum = @100.5;

Bool


NSNumber * boolNum = [NSNumber numberWithBool:YES];
        boolNum = @YES; 

More


NSNumber *piOverTwo = @(M_PI/2);

看到 @ 就是看到物件,直接把數值寫在後面,@100 就是一個 NSNumber 的物件,非常的合理和簡明。

NSArray 


1. NSString * str = @"4.4";
2. NSArray *  array = [NSArray arrayWithObjects:[NSNumber numberWithInt:2],@"Xcode",str,[NSDate date], nil];
2.1 NSArray * array = @[@2, @"Xcode",str, [NSDate date]];
2. 的寫法可以改成 2.1 用 @[, , ,] 來取代一堆的文字,變得多麼簡單一目瞭然。要注意的是 @[@"one"] 等同於 [NSArray arrayWithObject:@"one"] 並不是 [[NSArray alloc] initWithObject:@"one"] ,如果不是用 ARC 來管理記憶體的話,要多加小心,@[] 一開始就會被放到 autorelease pool 上,method 結束記憶體就沒了。

也許有讀者會好奇了,那 mutable 怎麼辦?@[] 是 NSArray 那 NSMutableArray 呢?有沒有另一個寫法?答案是,用 mutableCopy 如下

NSMutableArray * mArray = [@[@"one", @"two", @"three"] mutableCopy];
或是

[NSMutableArray arrayWithArray:@[@"one", @"two", @"three"]];
這樣一來 @[] 就會轉成 mutable array 了。
存取的時候非常方便,如下。

mArray[2] = @"four"; // write
    
NSLog(@"%@", mArray[2]); // read 

對變數直接用 [] 就可以存取某個 index 的值了,不只初始化好用,存取的時候更是方便。

NSDictionary


1. NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:@"value",@"key",@"Michael",@"name", nil];
2. NDictionary dict = @{@"key":@"value", @"name":@"Michael"}; 
dictionary 就是用 @{} 來表示,@[] 是 array,要注的是用 dictionaryWithObjectsAndKeys 的時候是先寫 object 再寫 key ,用  @{} 來表示的時候是先寫 key 再寫 value。
至於 mutable 的部分也是用 mutableCopy


NSMutableDictionary * myDict = [@{@"Name":@"Michael" } mutableCopy];
 myDict = [NSMutableDictionary dictionaryWithDictionary:@{@"Name":@"Michael"}];
存取 key 值的時候也很方便直接把 key 物件丟到 [] 裡。如下


myDict[@"Name"] = @"morning"; // write
    
NSLog(@"%@", myDict[@"Name"]); // read
就和 Javascript 的 associative array 一樣。
綜合 array 和 dictionary 來看初始化的時候用 @[] 和 @{} 來區別,但是存取值的時候都用 [],來操作,只是 array 的 [] 放的是整數值,dictionary 的 [] 放的是物件。

用新的語法還有什麼好處呢?來看下方的程式碼

-(id) getNil{
    return nil;
}

- (IBAction)insertNil:(id)sender {
    NSLog(@"%@", @[ [self getNil], @"hello",]);  // line a
    NSLog(@"%@", [NSArray arrayWithObjects:[self getNil], @"hello", nil]); // line b
} 
因為在 LLVM 4.0 之前的寫法 nil 在 array 或是 dictionary 裡面是當成結束,也就是說,萬一一開始就是 nil 那之後的元素就不理會,而新的語法可以在 compile 的時候找出奇怪的地方,因為新的語法裡不會有 nil 出現。如上方程式碼,[self getNil] 故意回傳 nil ,用新語法,line a 可以在 compile 時候就提出錯誤,而 line b 在執行的時候才會有可能被找到錯誤。
提筆至此,其實又可以增加一個 《需要換 Xcode 4.4 理由加一》
不過筆者不肯就此罷休,再提出一個問題來。自訂的 Class 想使用 [] 這個操作?

自訂 Class 使用 [] 

首先要分清楚,[] 裡面要放的東西,就我們所知有兩種,整數和物件。(從
array 和 dictionary 得知) 比如我想支援以下操作。

Car * car = [Car new];  // Any Class
car[1] = @"name";      // scalar write
NSLog(@"%@", car[0]);  // scalar read
就必需在自己的Class 覆寫,這兩個 mehtod。就可以用 [] 裡面放 NSInteger 了

- (id) objectAtIndexedSubscript: (NSInteger) index{
    return @"Car";
}
- (void) setObject: (id) thing  atIndexedSubscript: (NSInteger) index{
    NSLog(@"setting index %d with %@",index, thing);
}
如果 [] 要放的是物件,如下的操作

Car * car = [Car new];  // Any Class
car[@"dict"] = @"value"; // object write
NSLog(@"%@", car[@"good"]); // object read
就要覆寫以下兩個 method

- (id) objectForKeyedSubscript: (id) key{
    return [@"dict-like " stringByAppendingFormat:@"%@", key];
}
- (void) setObject: (id) thing forKeyedSubscript: (id<NSCopying>) key{
    NSLog(@"set %@ with %@", key, thing);
}
有沒有看到 setObject: forKeyedSubscript: 傳入的參數型別是 id<NSCopying> 。也就是說想用 myClass[key] = obj; 的時候,key 的 class 要有實作 <NSCopying> 提到的 required method 也就是 - (id)copyWithZone:(NSZone *)zone 。

好了,此次 Xcode 之旅就先暫時到這邊了,咱們下次再會,期待下次的 Xcode 之旅也會讓讀者們有所收獲。

最後請注意一下,筆者在寫這篇文章的時候,Xcode 4.4 (4F250) 上面的程式碼是可以執行的,但是換到 Xcode 4.4.1 (4F1003) 在幾個地方會有問題,@YES,@NO,或是 dict[@"key"], array[1] = @5 這種 subscript 的存取方式,可以參考 Apple 官方網頁,不過這些問題,"做夢夢到" 會在 Xcode 4.5 解決。