Showing posts with label iOS. Show all posts
Showing posts with label iOS. Show all posts

2013/08/06

紐約時報iOS行動軟體開發團隊的Objective-C程式碼撰寫風格與慣例

紐約時報iOS行動軟體開發團隊釋出他們的Objective-C程式碼撰寫風格與慣例,放在Git Hub上,供大家觀看、討論、分支、提出自己的意見。

我分支後將它翻成中文,放在這裡,敬請批評指教。

2013/07/31

[廣告] Objective-C 無痛入門(Objective-C Fundamentals)

嗨,我翻譯了一本書,在這裡打打廣告。

書名:Objective-C 無痛入門
原書名:Objective-C Fundamentals
作者:Christopher K. Fairbairn、Johannes Fahrenkrug、Collin Ruffenach
譯者:我
出版社:博碩
出版日期:2013年7月30日
頁數:416



這是Objective-C程式語言的入門書。

目錄

Part 1 起手撰寫Objective-C 程式
  Chapter 01 初次建立iOS 應用軟體
  Chapter 02 資料型別、變數與常數
  Chapter 03 第一次接觸物件
  Chapter 04 資料儲存與群集物件

Part 2 建立你自己的物件
  Chapter 05 建立類別
  Chapter 06 擴充類別
  Chapter 07 協定
  Chapter 08 動態型別檢查與執行時期型別資訊
  Chapter 09 記憶體管理

Part 3 充分利用軟體開發框架
  Chapter 10 錯誤與例外處理機制
  Chapter 11 鍵值編碼與NSPredicate
  Chapter 12 讀寫程式資料
  Chapter 13 Block 與Grand Central Dispatch
  Chapter 14 除錯技巧

2013/07/06

[廣告] 10 天就懂!一定學會 iPhone 程式開發的 40 堂關鍵課程

嗨,我審校了一本書,在這裡打打廣告。

書名:10 天就懂!一定學會 iPhone 程式開發的 40 堂關鍵課程
原書名:10日でおぼえるiPhoneアプリ開発入門教室
作者:関根 元和
譯者:廖文斌
審校:我
出版社:博碩
出版日期:2013年7月1日
頁數:448



這是一本iPhone軟體開發的入門書,屬於初心等級的著作,分成10章每章一個App主題,以製作樂趣為宗旨,包括多功能時鐘應用程式、樂器應用程式、地圖應用程式、相簿應用程式、等等,細分為40個LESSON,含有實際操作與理論課程,章末也會複習該記得的重點。

目錄如下:

Chapter 01 Hello World!:製作應用程式的基礎知識
LESSON01 製作什麼事都不做的應用程式
LESSON02 操作按鈕在畫面上顯示文字
LESSON03 使用各種UI 零件
LESSON04 用動畫顯示圖片

Chapter 02 製作Web 瀏覽器
LESSON05 顯示網站
LESSON06 加上頁面導覽
LESSON07 讓應用程式可以輸入URL
LESSON08 支援畫面旋轉功能

Chapter 03 製作多功能時鐘
LESSON09 使用分頁列
LESSON10 製作時鐘
LESSON11 製作計時器
LESSON12 製作碼錶

Chapter 04 製作復古相機應用程式
LESSON13 製作Action Sheet
LESSON14 拍下照片並加以選擇
LESSON15 顯示照片
LESSON16 圖片處理與儲存照片

Chapter 05 製作地圖應用程式
LESSON17 顯示地圖
LESSON18 更新當前位置
LESSON19 顯示目前的地址

Chapter 06 製作圖片檢視器應用程式
LESSON20 只顯示一張圖片
LESSON21 顯示多張圖片
LESSON22 讓圖片可以放大和縮小
LESSON23 省下無謂消耗的記憶體

Chapter 07 製作樂器應用程式
LESSON24 使用加速度感測器
LESSON25 在實機上進行除錯
LESSON26 播放音訊
LESSON27 在靜音模式下發出聲音

Chapter 08 製作Twitter 應用程式
LESSON28 取得網際網路上的資訊
LESSON29 使用Twitter 的API
LESSON30 解析取得的JSON 資料
LESSON31 顯示Tweet 列表

Chapter 09 製作音樂資料庫應用程式
LESSON32 使用CoreData
LESSON33 考慮資料結構
LESSON34 追加資料
LESSON35 編輯資料
LESSON36 排序資料

Chapter 10 歡迎來到App Store!
LESSON37 將應用程式本地化
LESSON38 在做好的應用程式中內嵌iAd
LESSON39 製作應用程式圖示
LESSON40 在App Store上發布應用程式


2013/07/05

Apple WWDC 2013中關於Objective-C的新東西

WWDC 2013落幕多時,影片可到此下載。

我看了402 What’s New in the LLVM Compiler、404 Advances in Objective-C、408 Optimize Your Code Using LLVM後,將重點簡述於下。

Objective-C語言居然登上TIOBE第三名,真是太厲害了。

新功能Module,在原本的Framework再包裝一層,使用起來更方便,更接近近代語言中「匯入模組」的形式;@import某標頭檔後,Xcode也會自動連結相對應的Framework,不需要自己到Link Binary With Libraries手動加入。目前,只有系統Framework可成為Module。

C相關語言的前置處理器(preprocessor)相當古老,使用文本置換的機制,大大拉長編譯時間,也不利於模組化,只不過積習難改,通常會透過預先編譯標頭檔的機制加以緩解。Module算是往前邁進一步,不錯。

新關鍵字instancetype,類別的-init方法原本是回傳id,但id可轉型為任何型別,造成困擾,將回傳型別換成instancetype後,就能編譯器處理,換成正確的型別。


除此之外,編譯器的部份也有不少增進的地方,錯誤與警告訊息更好更多了,能夠抓出更多錯誤。

Apple已經明確表示揚棄Garbage Collection了,全面採用ARC,Xcode 5也改用ARC。編譯器裡處理ARC的部份也更聰明了,現在可以看懂Core Foundation的命名慣例,當我們自動橋接,我們不需要自己加入__bridge了。

編譯器開始支援Apple的A6處理器(iPhone 5與新iPad),架構名為armv7s。處理器裡面其實有特別為向量打造的硬體加速能力,譬如Intel AVX(Advanced Vector eXtensions),Xcode 5開始支援AVX2。LLVM 5.0可分析strict aliasing(關鍵字strict)、支援LTO(Link-Time Optimization),在連結期間對整支程式進行最佳化,而不是分別針對每一支原始碼檔案最佳化。將迴圈向量化。Xcode 5不再支援GCC與LLVM-GCC。對C++11的支援也越來越好。另外還有許多最佳化參數,需視情況開啟或關閉,注意,有些最佳化參數,譬如關於浮點運算,可能會產生不一樣的結果。

2013/07/04

Objective-C迭代陣列

當手上有一堆東西時,常常就會需要作「迭代(enumeration)」的動作,譬如找出其中某些符合條件的東西、對全部東西執行某個動作、等等。

在Objective-C裡,經過時間演進後,有非常多方式可以進行迭代,底下一一描述。

NSArray *array = ...; //假設這是含有一堆字串的陣列

以迴圈手動撰寫,印出陣列裡每一個字串:
for(int i = 0, n = [array count]; i < n; i++){
    NSLog(@"%@", [array objectAtIndex:i]);
}

也可以用NSEnumerator:
NSEnumerator *enumerator = [array objectEnumerator];
NSString *s;
while(s = [enumerator nextObject]){
    NSLog(@"%@", s);
}

不過NSEnumerator已經被Objective-C 2.0新功能Fast Enumeration(for/in語法)取代了:
for(NSString *s in array){
    NSLog(@"%@", s);
}

不僅如此,自從iOS 4之後,還加入了block與新的API(非常多):
[array enumerateObjectsUsingBlock:^void(id obj, NSUInteger idx, BOOL *stop){
    NSLog(@"%@", obj);
}];

照理說,執行效能應該是後面的比前面快,不過我有時候測試一些特殊情況時,並不一定如此。不管如何,block是新機制,Apple也加入不少以block為基礎的API,應該是第一首選才是。

另外,NSDictionary與NSSet也會有差不多的東西,不贅述。

雖然是殺雞用牛刀,底下試試以GCD與Block來迭代陣列。

dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply([array count], q, ^(size_t i){
    NSLog(@"%@", array[i]);
});

不過使用的是concurrent queue,NSLog不一定會是從陣列索引值0依序輸出。可自行建立serial queue,便能得到想要的結果。


參考資料:

2013/06/27

[廣告] iOS6實戰:專家親授98個關鍵技巧打造超實用Apps(iOS in Practice)

嗨,我翻譯了一本書,在這裡打打廣告。

書名:iOS6實戰:專家親授98個關鍵技巧打造超實用Apps
原書名:iOS in Practice
作者:Bear Cahill
譯者:我
出版社:博碩
出版日期:2013年6月24日
頁數:352



目錄:
第1篇 準備工作
  第1章 起手開發iOS App
  第2章 建立iOS App

第2篇 實地演練
  第3章 視圖控制器與圖像,範例程式PicDecor
  第4章 存取電話簿/聯絡資訊,範例程式Dial4
  第5章 MapKit 與相機,範例程式WhereAmIParked
  第6章 設定、音訊、搖晃偵測,範例程式TimeDown
  第7章 Core Data、存取iPod、播放音樂,範例程式PlayMyLists
  第8章 推播通知與軟體內購買,範例程式Rock, Paper, Scissors
  第9章 Game Center排行榜與成就,範例程式Rock, Paper, Scissors
  第10章 iTunes API、iPad、iAd,範例程式MusicSearch
  第11章 群集視圖、社群、提醒事項、狀態回復,範例程式MeetSocial

附錄 iOS開發者計畫與App發佈

本書以實際App為範例,作者開發的範例程式皆上架到App Store,毫無虛假取巧的餘地,精心設計了10支App,並將一共98個技巧分別融入到各支App內進行示範。。除了基本一般的iOS SDK之外,還會介紹iOS 6裡的新功能。

2013/05/29

[廣告] iOS 6 SDK核心範例精研(The Core iOS 6 Developer's Cookbook, 4E)

嗨,我翻譯了一本書,在這裡打打廣告。

書名:iOS 6 SDK核心範例精研
原書名:The Core iOS 6 Developer's Cookbook, Fourth Edition
作者:Erica Sadun
譯者:我
出版社:悅知
出版日期:2013年5月16日
頁數:592



此次改版,作者Erica與出版社將原書拆解成三本書。

導論、介紹Objective-C、介紹Xcode、App如何上架、UIKit的基本功夫(視圖、控制器、基本視覺元件),大致上就是前一版(iOS 5那本)的第1~7章,獨立出來放在Learning iOS Development: A Hands-on Guide to the Fundamentals of iOS Programming裡,預計在2013年8月出版,約600頁。

而The Core iOS 6 Developer's Cookbook這本,更新到iOS 6與Xcode 4.6,並且拿掉一些最基本的入門內容,省下一些篇幅,讀者也省下一些錢。內容包含觸碰與手勢、自訂控制元件、各種UIKit元件、警示視圖、視圖與動畫過場效果、視圖約束規則(iOS 6新功能)、文字輸入、常用控制器(挑選照片、傳送電子郵件、社群網站狀態更新、等等)、表格視圖、群集視圖(iOS 6新功能)、捲動、畫面編排、等等iOS開發的核心知識,以及初階介紹Core Data與網路連線,所有的API都按照iOS 6 SDK加以更新,約570頁。我翻譯的是這本原文書。

目錄
第1章  手勢與觸控
第2章  建立與使用控制項
第3章  警示使用者
第4章  視圖與動畫效果
第5章  視圖約束規則
第6章  文字輸入
第7章  視圖控制器
第8章  常用控制器
第9章  無障礙存取
第10章 建立與管理表格視圖
第11章 群集視圖
第12章 初嚐Core Data
第13章 網路基本知識
附錄A  Objective-C字面值

進階內容則放在The Advanced iOS 6 Developer's Cookbook裡,於2013年3月出版,約530頁,內容包含Store Kit、Game Kit、Core Location、各種特殊用途的軟體開發框架。

關於其他學習Objective-C的iOS的資源,可以參考我寫的這篇。

2012/11/13

Objective-C也飛上雲端了(Objective-C in the Cloud)

Objective-C本來並沒有擠進主流語言的行列裡,但近年來在iOS的加持之下,Objective-C居然連續三級跳、跳到了TIOBE的第三名,真是可怕啊。

現在,Objective-C也要飛上雲端囉,有個新玩意兒叫做「Objective-C in the Cloud」。

PS 目前此雲端服務尚未開放測試,底下所言皆根據該官方網站所提供的資訊而來。

用的語言是Objective-C,所以瞄準的是熟悉iOS與Mac OS X軟體開發的對象,在自己的電腦上以Xcode進行開發,然後把程式碼丟上雲端。當然啦,光只有語言是不夠的,還會提供各種程式庫(library、framework),譬如說臉部辨識、PDF格式分析、等等的程式庫。

PS 這一點似乎有點爭議,如果是Apple的framework,Apple是否允許放到雲端上呢?

客戶端以HTTP形式存取你放在雲端上的服務(就跟一般網站/瀏覽器一樣),然後此雲端服務會把HTTP呼叫格式轉成NSDictionary,然後傳給你寫的程式碼(某物件、某方法),執行處理後,你把結果放在一個NSDictionary裡回傳,此雲端服務再轉成HTTP格式傳回給客戶端。

根據官方網站所寫,伺服器會是Mac Mini,放在德國。

你可以上傳原始碼(由它自動編譯)、或上傳編譯後的程式。

收費,有分$9、$49、$99不同等級,詳情請見官方網站。


2012/08/24

iOS儲存機密資料

怎麼在iOS上儲存機密資料呢,譬如密碼,這些資料必須加密後存放,不能被第三方輕易地竊取。到網路上搜尋後,大概會找到Apple官方的Keychain Service這套API,以及GenericKeychain這份範例程式碼。

經過一番奮鬥,詳細研讀Apple官方文件與網路上的教學文章後,我似乎勉強搞懂 SecItemCopyMatching、SecItemAdd、SecItemUpdate、SecItemDelete的用法與各種相關資料結構與常數的意義了。但是,這套API似乎太低階,當初設計的初衷大概考慮了讓多支軟體在同個環境內能共享或保護私密資料,對於我來說(只是想儲存專供我軟體使用的機密資料),非常難用,障礙很多,很容易出錯。

這種情形不就跟Joel說的一樣嗎,世界上有0.1%的人能學會C++寫程式,卻只有0.01%的人能搞懂ATL,而且每個人都留鬍子戴眼鏡,哇賽,還真的有這種讓人頭昏眼花的API啊。

或許Keychain Service還沒到那個地步,但實在不夠好用,還好,有人將Keychain Service雜七雜八的細節包了起來,提供一套輕便簡易的API,讓我們可以輕易地儲存機密資料,那就是STKeychain(前身為scifihifi-iphone)。

STKeychain原始碼放在GitHub的ldandersen / STUtils裡,位於子目錄Security裡,裡面有兩支檔案STKeychain.h與STKeychain.m,加入專案後,再加入Security.framework開發框架便完成了準備動作。(ldandersen / STUtils有許多子目錄,為其他不同功能,有興趣請自行試試看。)

因為我只使用STKeychain這兩支檔案,所以要把STKeychain.m前面的「#import "STUtils"」改成「STKeychain.h」。

STKeychain並未使用ARC,若你使用ARC的話記得在STKeychain.m檔加入編譯參數 -fno-objc-arc。

介面有三個,非常清楚。

首先是儲存,傳入你想儲存的username、password、serviceName,一般來說,username與serviceName是公開的,會儲存在別的地方,而這裡是把username與serviceName當做「鍵」的角色,將password儲存在安全的地方。參數updateExisting的意思是,若該筆資料已經存在的話要不要覆蓋過去,當出錯時可從參數error得到錯誤訊息,不需要就傳入nil;回傳BOOL代表儲存成功或失敗。
+ (BOOL)storeUsername:(NSString *)username andPassword:(NSString *)password forServiceName:(NSString *)serviceName updateExisting:(BOOL)updateExisting error:(NSError **)error;

然後是取出,傳入先前使用的username與serviceName,找出相對應的password回傳。
+ (NSString *)getPasswordForUsername:(NSString *)username andServiceName:(NSString *)serviceName error:(NSError **)error;

底下是刪除,應該無需多作說明。
+ (BOOL)deleteItemForUsername:(NSString *)username andServiceName:(NSString *)serviceName error:(NSError **)error;

這套API在iOS與Mac OS X上皆可使用,非常方便、簡單,太好囉,不用再跟Apple的Keychain Service奮鬥了!

2012/08/23

UIPickerView與NSTimer

朋友問我一個問題,在畫面上顯示UIPickerView,另外顯示一個UILabel進行倒數計時(譬如說從12.0秒倒數到0.0秒,每0.1秒更新)。

聽起來很簡單,不就用個NSTimer就搞定了嗎?可惜不是。

當倒數計時並更新UILabel時,若手指撥動UIPickerView,那麼倒數計時會暫停、UILabel也不會更新。



真正的原因我不清楚,大概是因為UIPickerView需要追蹤使用者的手指觸控事件,所以佔據了thread的runloop,使得NSTimer無法觸發吧。

解法之一是在另一個thread使用NSTimer:

float countdown = 120;

- (void)timerFireMethod:(NSTimer*)timer
{
    if(countdown > 0){
        countdown--;
        self.label.text = [NSString stringWithFormat:@"%2.1f", countdown/10];
        NSLog(@"%2.1f", countdown/10);
    }
    else{
        [self suspendTimer];
    }
}

- (void)suspendTimer
{
    if(_timer != nil)
    {
        [_timer invalidate];
        _timer = nil;
       
        CFRunLoopStop([_runLoop getCFRunLoop]);
       
        _timerThread = nil;
    }
}

- (void)_startTimerThread
{
    @autoreleasepool {

        _runLoop = [NSRunLoop currentRunLoop];
        _timer = [NSTimer scheduledTimerWithTimeInterval:0.1
                                               target:self
                                             selector:@selector(timerFireMethod:)
                                             userInfo:nil
                                              repeats:YES] ;
        [_runLoop run];
    }
}

- (void)resumeTimer
{
    if(_timer == nil)
    {
        _timerThread = [[NSThread alloc] initWithTarget:self
                                               selector:@selector(_startTimerThread)
                                                 object:nil];
        [_timerThread start];
    }
}

其中resumeTimer、suspendTimer是使用介面,把你想要執行的程式寫在timerFireMethod:裡。

解法之二是使用GCD(Grand Central Dispatch):

float countdown;

-(void)tick
{
    self.label.text = [NSString stringWithFormat:@"%2.1f", countdown/10];
}
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
  
    countdown = 120;
  
    queue = dispatch_queue_create("com.example.MyQueue",  NULL);
  
    ds_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
  
    dispatch_source_set_timer(ds_timer,  dispatch_time(DISPATCH_TIME_NOW,  0),  0.1*NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(ds_timer,  ^(){
        if(countdown > 0){
            NSLog(@"tick %2.1f", countdown/10);
            countdown--;
            [self performSelectorOnMainThread:@selector(tick) withObject:nil waitUntilDone:YES];
        }
        else{
            //over
        }
    });
    dispatch_resume(ds_timer);
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
  
    dispatch_suspend(ds_timer);
    dispatch_release(ds_timer);
    dispatch_release(queue);
}

利用timer dispatch source便能每隔一段時間產生出某事件,然後指定想要執行的程式碼,要注意的是,想要更新iOS的畫面時,必須在main thread裡進行,所以上面程式碼使用了 [self performSelectorOnMainThread:@selector(tick) withObject:nil waitUntilDone:YES];這個方法。

應該也能以NSOperation與NSOperationQueue解決,但我還沒試。


參考文章:


使用ARC時的一個小陷阱:UIColor回傳的CGColor

自從開始使用ARC(Automatic Reference Counting)後,我覺得這算是Objective-C的一個重大進步,但是,但是,並不代表寫程式時不需要思考如何管理物件與記憶體了,還是要跟一堆關鍵字(strong、weak、__bridge_transfer、等等)打交道,還是要遵循一堆使用記憶體的相關守則與慣例,以前要想著release與retain,現在則要想著物件彼此間的關係圖。

底下記錄一個絆倒我的ARC陷阱,跟UIColor回傳CGColor有關。

在某個方法裡,我建立了UIColor物件,並以它的CGColor方法回傳CGColorRef,然後使用。

在某方法裡:
{

  CGColorRef cgcolor = [UIColor colorWithRed: 0.2 
                                                                  green: 0.3 
                                                                     blue: 0.4 
                                                                   alpha: 1.0].CGColor;

  [[self.view layer] setBackgroundColor: cgcolor];
}

糟了,發生記憶體錯誤當掉了,怎麼會這樣呢?

使用ARC以前:上面程式碼裡的UIColor物件會被autorelease,我們知道,在方法回傳結束前,這個物件會是存在的,所以cgcolor會指向存在的物件。

使用ARC以後:UIColor物件並沒有被任何變數指向,所以,ARC很聰明地將它釋放掉了,哈哈。

解法很多,我比較想採用的是這一個:

{
  UIColor color = [UIColor colorWithRed: 0.2 
                                                       green: 0.3 
                                                          blue: 0.4 
                                                        alpha: 1.0];

  [[self.view layer] setBackgroundColor: color.CGColor];
}

這麼一來,color是個strong變數,可以確保該物件不會被釋放,直到用完為止。

其他解法還有:以CGColorRetain與CGColorRelease抓住cgcolor。

另外,底下的寫法看似合理,但卻是個有問題的寫法:

{
  UIColor color = [UIColor colorWithRed: 0.2 
                                                       green: 0.3 
                                                          blue: 0.4 
                                                        alpha: 1.0];
  CGColorRef cgcolor = color.CGColor;
  [[self.view layer] setBackgroundColor: cgcolor];
}

color物件在呼叫CGColor方法後就無處使用,所以ARC很可能會在setBackgroundColor之前就是放掉color物件,以致於cgcolor指向不存在的記憶體空間。



參考文章:

2012/07/08

Objective-C在Xcode 4.4版裡的新增功能

2012年Apple年度大會WWDC(Apple Worldwide Developers Conference)的影片可以下載囉。

底下記錄一些未來的Objective-C將會擁有的新功能與新特色,在Xcode版本4.4以後的編譯器才有這些新功能,編譯出來的程式可以相容於先前版本的系統。

參考影片:
Session 405 - Modern Objective-C
Session 413 - Migrating to Modern Objective-C






首先,跟類別裡方法的宣告順序有關。譬如說,在類別裡有個私有的方法,該怎麼辦?

// SongPlayer.h
@interface SongPlayer : NSObject
{
}
- (void)playSong:(Song *)song;
@end

// SongPlayer.m
@implementation SongPlayer
- (void)playSong:(Song *)song
{
  NSError *error;
  [self startAudio:&error];
  //...
}

- (void)startAudio:(NSError **)error
{
  //...
}
@end

其中playSong是公開的介面,而startAudio是內部私用的方法。上面這段程式碼會有編譯錯誤,因為playSong在startAudio宣告之前就呼叫了。

如果能將startAudio搬到前面去就可解決,但有時候做不到或不想這麼做,一般的解法是運用class extension,修改如下:

// SongPlayer.h
@interface SongPlayer : NSObject
{
}
- (void)playSong:(Song *)song;

@end

// SongPlayer.m
@interface SongPlayer ()
- (void)startAudio:(NSError **)error;
@end

@implementation SongPlayer
- (void)playSong:(Song *)song
{
  NSError *error;
  [self startAudio:&error];

  //...

}

- (void)startAudio:(NSError **)error
{
  //...

}
@end

我們可以把私用方法宣告在class extension(@interface SongPlayer () ... @end)裡,就可解決此問題。

但新的Objective-C更強,它直接幫我們處理好了,編譯器會先解析各方法的宣告(方法名、回傳型別、參數型別),然後再解析方法的內容,這麼一來,一開始的程式碼就不會有錯誤了。


新的Objective-C的enum有了不錯的進步,新型的enum可如下定義:

enum FruitEnum : NSUInteger
{
  FruitEnumApple,
  FruitEnumBanana,
  FruitEnumCherry,
  FruitEnumBlueberry,
  //...
} FruitEnum;

其名為fixed underlying type enum。

有了這種enum後,Xcode在補足程式碼(code completion)時就更聰明了,而且,編譯器也能作檢查型別,譬如說把某enum值指定給另一個enum型別的變數,就會出現錯誤訊息(編譯器參數為-Wcovnersion),還有,以switch根據某enum型別作判斷的話,若少寫某enum值時編譯器也會提醒你(編譯器參數為-Wswitch)。


對於property也有很多新東西。

原本會這麼寫:

//Person.h
@interface Person : NSObject
{
  NSString *_name;

}

@property (strong) NSString *name;
@end

//Person.m
@implementation Person

@synthesize name = _name;

@end

可以把instance variable的宣告改放在@implementation裡:
//Person.h
@interface Person : NSObject
{
  NSString *_name;

}

@property (strong) NSString *name;
@end

//Person.m
@implementation Person
{
  NSString *_name;
}

@synthesize name = _name;

@end

而且,既然用了@synthesize,根本就不需要自己宣告instance variable了:
//Person.h
@interface Person : NSObject
{
  NSString *_name;

}

@property (strong) NSString *name;
@end

//Person.m
@implementation Person
{
  NSString *_name;
}


@synthesize name = _name;

@end

以上是本來就有的,現在,在Xcode 4.4(與之後的版本),連@synthesize都可以省略了:
//Person.h
@interface Person : NSObject
{
  NSString *_name;

}

@property (strong) NSString *name;
@end

//Person.m
@implementation Person
{
  NSString *_name;
}


@synthesize name = _name;

@end

也就是說,synthesize是"預設"的行為了,原本property要寫好幾行程式,現在只需一行即可,編譯器會自動加入:

@synthesize name = _name;

預設會在property名字前面加上底線「_」作為instance variable的名字。

注意,為了相容於舊版,若你寫了
@synthesize name;
則等同於
@synthesize name = name;


object literal(這是我覺得早就應該加入的功能)。

首先是NSNumber,原本要這麼寫:
NSNumber *n1 = [NSNumber numberWithInt:1234];
NSNumber *n2 = [NSNumber numberWithFloat:1234.56f];
NSNumber *n3 = [NSNumber numberWithBool:YES];
等等...

新版的只需寫:
NSNumber *n1 = @1234;
NSNumber *n2 = @1234.56f;
NSNumber *n3 = @(YES); // iOS 5寫@YES不行
等等...

不僅如此,以下的運算式都會變成NSNumber:
@( M_PI / 6 )
@( "0123456789ABCDEF"[x % 16] )
@( NSWriteDirectionLeftToRight )

@( getenv("PATH") ),這個會變成NSString

同樣的,NSArray,原本要寫很多程式碼,要擔心有沒有在末端加上nil,現在可改成:

NSArray *array1 = @[]; // 空的陣列
NSArray *array2 = @[a]; // 只含有a物件的陣列
NSArray *array3 = @[@"a", @"b", @"c"]; // 含有三個字串的陣列

既然NSArray出現了,沒道理NSDictionary會缺席啊,同理,NSDictionary也有了類似的新語法:

NSDictionary *dict1 = @{};
NSDictionary *dict2 = @{k1:o1};
NSDictionary *dict3 = @{k1:o1, k2:o2, k3:o3};

id value = aDictionary[@"key"]; // 讀取
aMutableDictionary[@"key"] = newValue; // 寫入


subscripting

NSArray的物件也可以用[]來存取其內的東西了,

NSArray *songs = @[@"song1", @"song2", @"song3"];

NSString *s1 = songs[0]; //讀取

songs[0] = @"newSong"; //寫入

不只NSArray可以利用[]語法,你自己寫的類別也可以喔,只需實作底下的方法即可:

-(元素型別)objectAtIndexedSubscript:(索引型別)idx;
-(void)setObject:(元素型別)object atIndexedSubscript:(索引型別)idx;

嗯,還不錯,程式碼可以大幅簡化囉。

2012/07/06

Xcode與Clang(LLVM)輔助開發的小東西(#pragma、#warning、#error)

注意,我的開發環境是Xcode 4.2並使用Clang(LLVM)編譯器3.0版。Apple應該不太可能再回到GCC了,所以就不管了。

首先,可利用#warning會產生警告訊息,但還是能通過編譯建置成功。譬如說底下的程式碼:

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
  
#warning need to do some cleanup
}

編譯後就會出現在Issue Navagator裡。


撰寫程式碼時,有時候會突然想到當下無法處理的東西、或是想做個記號留待之後再處理,此時就可以用#warning。

但若改成#error的話,就會是錯誤訊息,通不過編譯建置。

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
  
#error need to do some cleanup
}



程式越寫越多,要怎麼分類管理呢?此時可以利用#pragma mark。譬如說如下的程式碼:

#pragma mark - Something Stupid
-(void)stupidA
{
}

-(void)stupidB
{
}

#pragma mark Something Smart
-(void)smartA
{
}

-(void)smartB
{
}
@end

Xcode的編輯器解析之後,就能呈現出如下的結果。


其中,在mark的後面若是減號「-」的話,就會有一條分隔線。然後秀出後面的文字。可利用#pragma將方法分門別類,找起來就輕鬆多了。

不僅如此,我們還能用MARK:、TODO:、FIXME:、!!!:、???:作更進一步的劃分,譬如說:

#pragma mark - Something Stupid
// MARK: markmarkmark
// TODO: todotodotodo
-(void)stupidA
{
}

// FIXME: fixmefixmefixme
-(void)stupidB
{
}

#pragma mark Something Smart
// ???: ?????????
-(void)smartA
{
}

/// !!!: !!!!!!!!!
-(void)smartB
{
}

呈現效果如下:


比較常用的是TODO:跟FIXME:。在開發時難免忘東忘西,若能直接在程式碼裡寫下來,這樣不是很棒嗎?

編譯器很聰明地幫我們找出有宣告卻沒使用的變數,並且吐出警告訊息,一般來說這是我們想要的,但在極少數的情況下,我們可能希望編譯器不要這麼煩人,此時可利用#pragma unused:

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
   
    int x;
    #pragma unused (x)
}

這麼一來,編譯器就不會對x作出未用變數的警告了。

不僅如此,我們還能關閉其他編譯器的警告與錯誤訊息。譬如說:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmultichar"

char b = 'df'; // no warning.

#pragma clang diagnostic pop

以上的寫法能夠暫時關閉multichar這個警告訊息。先用push把目前的設定儲存起來,然後暫時忽略某些警告與錯誤訊息,然後再以pop回復先前的設定。

能夠關閉的訊息很多,詳情請參考clang使用手冊。

參考資料:

2012/04/14

Objective-C:雖然NSString是唯讀的,但內容還是可能改變

在Objective-C裡,很多類別常常有唯讀版與可變版,譬如NSString與NSMutableString、NSArray與NSMutableArray、NSDictionary與NSMutableDictionary,一般來說,唯讀版的物件建立之後就不能改變,可變版的物件建立後,可以隨心所欲地進行修改。

一旦建立出NSString物件,NSString類別並沒有提供任何方法讓我們修改其中的字串,但要小心,裡頭的字串還是有可能會改變的,以底下範例說明。

假設有個Person類別,有兩個屬性name(名字)與address(住址)。其中name屬性使用retain,address使用copy,也就是說,當你指定一個NSString物件給name時,它只會記住該物件指標並增加參考計數,而指定一個NSString物件給address時,它會傳送copy訊息給該物件,得到一份拷貝。

// Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    NSString *name;
    NSString *address;
}

@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *address;

@end


// Person.m
#import "Person.h"

@implementation Person
@synthesize name;
@synthesize address;

-(NSString *)description
{
    return [NSString stringWithFormat:@"name(%@), address(%@)", name, address];
}

@end


// main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   
    NSMutableString *sname = [NSMutableString stringWithString:@"Amanda"];
    NSMutableString *aname = [NSMutableString stringWithString:@"Taiwan"];
   
    Person *person = [[Person alloc] init];

    person.name = sname;
    person.address = aname;
    NSLog(@"1: person=%@", person);
   
    [sname appendString:@"XXX"];
    [aname appendString:@"YYY"];
    NSLog(@"2: person=%@", person);
   
    [person release];
    [pool release];
    return 0;
}

首先建立兩個NSMutableString物件sname與aname,分別指定給person物件的name與address,然後印出person物件。接下來以NSMutableString介面修改sname與aname,然後再印出person物件,你會發現,person的name變了,address沒變。

程式輸出如下:

2012-04-14 23:01:47.603 TestNSString[24655:903] 1: person=name(Amanda), address(Taiwan)
2012-04-14 23:01:47.606 TestNSString[24655:903] 2: person=name(AmandaXXX), address(Taiwan)

結論,不要以為的物件的類別為NSString就不會改變,若要確保不變,屬性可使用copy宣告。

2012/04/09

[廣告] iOS SDK 開發範例大全(The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers, 3/e)

嗨,我翻譯了一本書,在這裡打打廣告。

書名:iOS SDK 開發範例大全
原書名:The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers, 3/E
作者:Erica Sadun
譯者:我
出版社:悅知
頁數:864



這本是iOS(iPhone、iPod touch、iPad)軟體開發的入門書,更新到iOS 5、Xcode 4.2、Objective-C 2.0與block與ARC(automatic reference counting),也有講解Interface Builder(已經整合進Xcode)的新玩意兒storyboard,範例很多,內容涵蓋UI介面設計、各種視覺元件、文字標籤、表格、畫面轉換的過場動畫、自製控制項、記憶體管理、資料儲存、App Store上架、多點觸控、手勢、臉部辨識、裝置規格設定、查詢網路連線狀態與非同步下載、等等等等,極為豐富。

我在翻譯時,還發生一件事情。我拿到原文書後,發現裡面有很多地方缺失漏掉了,但不是作者的錯,應該是出版社進行編輯排版時發生錯誤,這讓我很驚訝,原文書出版社Addison-Wesley,是我心中覺得不錯的出版社,居然也會搞這種烏龍。後來更正後,也把之前印錯的書通通回收,重新出版,嗯,處理的還不錯。

關於iOS的入門書有很多,原文書中另外一本有名的是"探索 iPhone 4 程式開發實戰"(Beginning iPhone 4 Development: Exploring the iOS SDK),已經有iOS 5的版本(Beginning iOS 5 Development: Exploring the iOS SDK),但中文翻譯還沒出。

(2012.06.23更新:Beginning iOS 5 Development: Exploring the iOS SDK的繁體中文翻譯本已經出版了,書名是"探索 iOS 5 程式開發實戰")


相關連結:
1. 悅知網站關於此書的介紹。
2. 天瓏書局。
3. 博客來、金石堂、TAAZE讀冊生活。
4. Amazon(原文書)。

關於其他學習Objective-C的iOS的資源,可以參考我寫的這篇。

2012/03/23

Objective-C與iOS的學習資源

問:學習Objective-C的書籍?
答:

Learn Objective–C on the Mac by Mark Dalrymple and Scott Knaster, Apress.
這本的內容是Objective-C跟一些基本的Cocoa Foundation Framework,是學習Objective-C的入門書,這本書假設你已經有C語言的基礎,所以不適合沒有任何程式語言基礎的人看。本書在我認為這是本很棒的書,平易近人,值得推薦。

另外,本書出版日期是2008.12,是在Mac OS X Snow Leopard v10.6(2009.08)之前,也就是說,本書沒有講Objective-C新加入的功能與特色,譬如block(在OS X v10.6與iOS 4.0才有)。

這本書有第二版了,書名為Learn Objective-C on the Mac: For OS X and iOS,出版日期2012.06,太棒了,包含了所有新特色新功能,block、ARC、等等。

Programming in Objective-C 2.0 2nd Edition by Stephen G. Kochan, Addison-Wesley.
這本的作者認為太熟C反而妨礙以Objective-C的方式去思考,所以不假設你會C。在很久以前,講Objective-C的書籍似乎只有這一本,所以那時很多人也只能看這本。我認為這本寫的中規中矩,不錯,而且不斷地更新。這本書有官方論壇,作者會親自回答問題喔。

第二版有中文翻譯本。
第三版已經在2011.06出版囉,有講block。
第四版已經在2011.12出版囉,有講block與ARC。有中文翻譯本:精通Objective-C 程式設計 第四版。
第五版已經在2012.12出版囉,中文翻譯本:精通 Objective-C 程式設計 第五版。

Learning Objective-C 2.0: A Hands-On Guide to Objective-C for Mac and iOS Developers by Robert Clair,也是學習Objective-C不錯的入門書,裡面有介紹剛剛進入mac os x與iOS的開發環境,需要熟悉的一些基本東西與觀念,例如什麼是bundle、framework、AppKit、Core Foundation等等,前面兩本的重心都是放在Objective-C上,這本則加入了開發iOS的基礎知識,算是不錯的選擇。

Objective-C for Absolute Beginners: iPhone and Mac Programming Made Easy by Gary Bennett, Brad Lees, and Mitchell Fisher, Apress.
看到這本書的書名你就能猜到,專門為想寫iPhone與Mac軟體的初學者入門書,從最基本教起,譬如說書一開始還講解什麼是演算法、什麼是軟體開發流程、什麼是bit、十進位與二進位的轉換等等,但頁數卻不到三百,也就是說,講的都非常簡單非常基本。呃,我不會推薦你看這本。

Objective-C Phrasebook by David Chisnall, Addison-Wesley.
使用Objective-C寫程式,多年以後,自然而然會有慣用法、經驗累積、最佳的程式片段,這本書就是作者的心得精華,裡面每一章都很短,範例程式也很短,內容涵蓋Objecitve-C執行週期程式庫、記憶體管理、property lists、key-value coding、各種基本的類別(數字、字串、陣列、日期時間等等)。不錯的書。

Pro Objective-C Design Patterns for iOS by Carlo Chung, Apress.
這本書就是講GoF Design Patterns裡面的那23個設計範式,只不過改以Objective-C來表達,並以iOS的Cocoa Touch為基礎,書裡的程式碼都是要在Xcode與iOS SDK上跑的。

Cocoa Design Patterns by Erik M. Buck與Donald A. Yacktman,Addison Wesley 2009年9月出版。沒看過,看書名應該是Mac上的Cocoa的設計模式。


Cocoa設計模式,譯者賀以翔、林銘鴻、吳國慶,上奇2011年12月出版。上一本的中文譯本。

Pro Objective-C for Mac and iPhone by Michael Ash and James Dovey, Apress. 尚未出版。看起來應該是進階的書。

Objective-C For Dummies by Neal Goldstein, For Dummies. 沒看過。

Objective-C Programming: The Big Nerd Ranch Guide by Aaron Hillegas and Mark Fenoglio, Addison-Wesley。
這本書應該是寫給沒碰過C、沒碰過Objective-C、沒碰過Xcode、沒碰過iOS的人看的,不到300頁的篇幅,卻要介紹這麼多東西,很厲害,言簡意賅,不廢話。作者的目的應該是打算用最少篇幅引人入門,安裝Xcode、學習基本的C語言、然後是Objective-C與Foundation framework,然後是建立iOS與Mac應用程式,頁數不多,所以講的都是最基本最重要的。
我個人不太喜歡這樣的書籍,因為我還是要再買一本好好介紹Objective-C的書、還是要再買一本講解開發iOS的書。不過這本的優點是,不到300的頁數,很快就能翻過一遍,就能對iOS開發需要的程式能力有基本的概念,不錯。

詳解 Objective C─iPhone / iPad / Mac OS X 標準程式設計與實作 by 荻原剛志,博碩出版。日文翻譯過來的,沒看過。

Objective-C 2.0 iPhone/iPad/Max OS X 程式設計講座,荻原剛志 著、鄭英龍、連軒甫 譯,博碩。上一本的更新版,加入Objective-C 2.0的新功能。

學會 Objective-C 的 24 堂課─撰寫 iPhone 應用程式的初體會,第二版,by 蔡明志,碁峰出版。
寫的中規中矩,可以考慮。本書從C語言介紹起,然後是Objective-C,然後是一些Foundation Framework,最後有一章的篇幅稍微介紹iPhone的開發。
本書第二版雖然在封面上印上"針對XCode 4.x全新改版",但我只發現iPhone那一章更新了。關於Objective-C的部份應該沒變。沒有介紹Objective-C的新功能:block、Automatic Reference Counting(ARC),沒有Interface Builder的新功能storyboard。

Objective-C 與 iOS 開發入門 by Michael Pan 潘聖文,藍海文化出版。
這本書約400頁,其中300頁左右介紹iOS開發,100頁左右介紹Objective-C,應該是為了介紹iOS的部份,所以才特別加上介紹Objective-C那部分,光就此書有涵蓋的內容來看,寫的還算不錯,但是篇幅不夠,以致於Objective-C講的太少;iOS的部份還OK,但300頁不太夠。我是覺得有點可惜了,被篇幅限制住了。

輕鬆學 Objective C-開發你的 iPhone/iPad 應用程式 by 楊正洪、鄭齊心、李建國,上奇出版。
簡體版翻譯過來的,裡面有少數幾個名詞依然是大陸用語,不過應該不影響閱讀。這本以Objective-C與Foundation Framework為主,只有一兩章才是iOS開發。我只有翻閱過,不能做評論,大家到書店翻翻看合不合胃口吧。

Objective-C 2.0 Essentials,可線上閱讀的著作,但不全,可購買完整版,內容範圍很廣。

這邊有一張Objective-C的小抄,Ray Wenderlich寫的。


然後看Apple文件(免費下載或線上閱讀),這些算是官方文件,內容精鍊,有疑惑時都要來這裡。
The Objective-C Programming Language,對語言本身有什麼疑義,找這裡就對了。
Memory management Programming Guide,Cocoa(Foundation+AppKit)的物件記憶體管理通則。
Objective-C Runtime Programming Guide,除了語言(compiler)外,還要有runtime環境,這文件告訴你Objective-C在執行時需要的支援,message forwarding的機制,dynamic method resolution的機制等等。
Objective-C Runtime Reference,上一份文件的補助,參考文件,詳列runtime library中實作的函式。
Object-Oriented Programming with Objective-C,顧名思義,Objective-C與物件導向。

這裡CocoaChina Wiki有把一些蘋果官方文件翻譯成中文。


問:Objective-C有1.0與2.0之分?
答:在2007.10,Apple推出Mac OS X 10.5,也推出Objective-C 2.0,目前只有Xcode中的compiler(Apple修改過的gcc)以及clang(llvm)能夠吃2.0,也只有Mac OS X 10.5, iPhone, iPad的runtime環境可以跑2.0。

2.0多了這些東西:garbage collection、properties、non-fragile instance variables、fast enumeration。

另外,後來Objective-C又加入新的功能特色block與ARC(automatic reference counting)。

PS 嚴格說來,block應該算做C語言的擴充功能。

問:有線上的教學文件嗎?
答:網路上可以找到很多,請自行判斷優劣。

問:優良的部落格?
答:Cocoa Manifest、Cocoa With Love、Cocoa Samurai、Matt Gemmell、Cocoa Is My Girlfriend、mikeash的NSBlog。

問:還有問題怎麼辦?
答:網路上有很多Q&A論壇,譬如Stack Overflow,這網站上有很多人討論iOS軟體開發。

問:想在iOS(iPhone, iPod Touch, iPad)上開發,有何教學文件?
答:

1. The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers by Erica Sadun。
學習iOS軟體開發不錯的入門書,從iOS SDK 2.x開始一直更新到現在的iOS 6.x。從基本講起,範圍廣泛,這本範例很多。

iOS 5的中文翻譯本,書名是"iOS SDK 開發範例大全"。

iOS 6的原文書The Core iOS 6 Developer's Cookbook,於2012年12月出版。
注意:此次改版,作者Erica與出版社將iOS軟體開發分成三本書:

導論、介紹Objective-C、介紹Xcode、App如何上架、UIKit的基本功夫(視圖、控制器、基本視覺元件),大致上就是前一版(iOS 5那本)的第1~7章,獨立出來放在Learning iOS 6: A Hands-on Guide to the Fundamentals of iOS Programming裡,預計在2013年7月出版,約600頁。

而The Core iOS 6 Developer's Cookbook這本,內容包含觸碰與手勢、自訂控制元件、各種UIKit元件、視圖與動畫、文字輸入、常用控制器、表格視圖、捲動、畫面編排、等等iOS開發的核心知識,以及初階介紹Core Data與網路連線,約570頁。詳細目錄在此。

進階內容在The Advanced iOS 6 Developer's Cookbook裡,預計在2013年3月出版,約500頁,內容包含Store Kit、Game Kit、Core Location、各種特殊用途的軟體開發框架。

2. Beginning iOS 5 Development: Exploring the iOS SDK by David Mark, Jack Nutting, Jeff LaMarche。
這本是學習iOS不錯的入門書,不斷地改版更新,從一開始的iPhone OS 2.x、3.x,到現在的iOS 4.x、5.x、6.x版。
iOS 4有中文翻譯本。
iOS 5的中文翻譯本出版了,書名是"探索 iOS 5 程式開發實戰"。
iOS 6的原文書,預計在2013年1月出版。

這本書的姊妹作為More iOS 6 Development: Further Explorations of the iOS SDK,2012年12月出版,內容比較進階。

3. iOS Programming: The Big Nerd Ranch Guide by Joe Conway and Aaron Hillegass。
也是學習iOS軟體開發的入門書,內容風格與前兩本不同,請讀者自行翻閱看看,看看哪本比較適合您。

Third Edition內容涵蓋iOS 5與Xcode 4.3,於2012年3月出版。

4. 美國史丹佛大學跟蘋果公司合作開課。iPhone Application Development (Winter 2010),YouTube上課錄影或是到iTunes上,這裡有投影片與作業,這邊有Inside網站刊載的心得筆記(中文)。這課程還有繼續開,但最新的上課內容並沒有開放出來。

5. 熱心人士自己錄製的教學錄影Learning iOS Development,放在YouTube上。

6. 其他,自己找找囉,這篇列出32個開發資源網站,非常棒。

問:有哪些線上資源、網站或部落格?
答:

在Windows上寫Objective-C程式(使用GNUstep與Clang、LLVM)

之前我寫了一篇Objective-C on Windows,以GNUstep在Windows XP上寫Objective-C程式,但是Objective-C已經加了很多新東西,而GNUstep裡的gcc並不提供,所以,這篇要介紹GNUstep,再加上新一代的編譯器架構Clang與LLVM(這也是Apple在新版Xcode裡預設使用的編譯器),這樣就能有Objective-C 2.0的功能,以及block與ARC(automatic reference counting)。

問:想開發iPhone或iPad或Mac的軟體,該怎麼辦?
答:使用Apple官方的軟體開發工具Xcode,只要到Apple公司的開發者網站,註冊一下(免費),即可下載最新版的Xcode。Xcode只能在Mac OS X(作業系統)上運行,所以要買一台Mac機器(硬體)。

PS 最新版的Xcode可以直接從Mac App Store下載。

問:哇,這麼多種漂亮的Mac,應該買哪一台啊?
答:有錢的話就買最貴的那一台*_*。


問:什麼是Xcode?
答:Xcode是Apple公司官方的軟體開發工具組,可開發在Mac、iPhone、iPad的軟體,是一個總稱,裡面包含很多東西,有整合式開發編輯器(IDE,也叫做Xcode)、視覺化使用者介面開發工具(Interface Builder)、compiler、linker、debugger(gcc、gdb、llvm...)等等、還有模擬器,以及各種framework(函式庫、類別庫、API)。

這是Xcode IDE,負責管理專案檔案、編輯、以及各種設定,從這裡進行編譯除錯執行。


這是Interface Builder,視覺化使用者介面設計,使用拖拉放的方式來操作。(在Xcode 4以前是支獨立的軟體,之後Xcode IDE已經整合Interface Builder。)


這是模擬器,不用買一支iPhone也可以進行開發iPhone軟體喔。


也就是說,如果你有一台Mac電腦(花錢買),下載Xcode(免費下載)後,就可以開始開發,在模擬器上執行看到成果。但是,如果想在iPhone實機上執行你寫的程式的話,那就要加入Apple的iOS Developer Program(要錢,一年要付$99),至於加入、付錢、設定、下載軟體到手機上的過程,本篇不介紹。

問:想先學學Objective-C程式語言,還不想砸錢買Mac,有辦法在Windows上寫Objective-C程式嗎?
答:有,就是這篇的重點了。

問:聽說gcc可以編譯Objective-C,所以在Windows上裝cygwin,裡面有gcc,就可以寫Objective-C程式了?
答:cygwin的gcc的確可以編譯Objective-C程式,但光裝cygwin並不會有任何的物件類別庫(library、class library、framework),所以也就沒有各種基本的物件類別可以用,沒有NSLog可以呼叫(想像成c的printf);沒有NSObject可以繼承,讓你沒辦法立即開始寫自己的物件;沒有Foundation.h(想像成c的stdio.h)連preprocessor都過不去,更別提compiler了。所以只有compiler是不夠的。而且,一般版本的gcc裡頭的Objective-C部分,很舊,沒有許多Apple加入的新功能。

同樣的,若只有clang(llvm)也不夠。

問:所以除了compiler還需要?
答:還需要一套framework,裡面會有基本的物件類別。如果是裝Xcode就會有Cocoa for Mac、Cocoa Touch for iPhone。Cocoa大致上分為Foundation跟AppKit兩個部分,AppKit是GUI元件與較高階的元件,而Foundation就是一堆基本的物件類別,例如NSObject、NSString、NSArray、NSNumber等等;而Cocoa Touch分成Foundation跟UIKit,差不多的意思。

問:聽說Cocotron...?
答:Cocotron也是一個Objective-C的開發環境,其目標是讓開發出來的軟體可以在各種平台上執行,例如Windows,但其本身還是要搭配Xcode使用,所以不符本篇主題。

問:那所以咧?
答:使用GNUstep,可在unix-like與Windows上使用,有Cocoa API,也有一些開發工具(類似Xcode提供的工具)可以用,但本篇重點是在Windows上寫一支Objective-C的hello world!程式,所以會用命令列模式shell,只會使用compiler的部份(也是gcc),以及鏈結Cocoa API中Foundation的部份,也就是說不理會AppKit的部分,也不會介紹GNUstep提供的開發工具(Gorm, ProjectCenter...)。

因為GNUstep裡的gcc,其Objective-C的部份很舊了,無法編譯Objective-C的新功能與特色,所以除了GNUstep,我們還需要安裝clang(llvm)。

問:GNUstep可在哪些版本的Windows上跑?
答:官方網站上說在WinXP與Win2K測試過,我的電腦是Windows XP。

問:怎麼安裝GNUStep?
答:到GNUstep網站的Windows下載區,下載下面三個安裝套件。
1. GNUstep MSYS System,53MB,基本環境與命令列shell。
2. GNUstep Core,9MB,函式庫、類別庫。
3. GNUstep Devel,44MB,開發工具,gcc、make、gdb等等。
注意:請按照順序安裝。


把三個都安裝在同一個目錄(預設值是C:\GNUstep),安裝時也都是按Next即可。安裝後執行「開始-程式集-GNUstep-shell」,會出現一個命令列畫面,恭喜你,已經成功了一半。


問:怎麼安裝clang(llvm)?
答:
首先,我們將下載原始碼自行編譯,編譯時需要很多工具,前面安裝的GNUstep幾乎都有了,但還缺個python,請到python官方網站下載頁面,下載python的windows版,我下載的是2.7.2版。安裝後,修改環境變數(開始-設定-控制台-進階-環境變數),將「C:\Python27」(這是預設的安裝路徑)加入「PATH」。

然後,開啟「程式集-GNUstep-shell」,依序執行下列指令:

$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm

$ cd llvm/tools

$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang

第一道指令會下載llvm(約106 MB),第二道指令切換目錄,第三道指令下載clang(約65 MB)。

然後,我們需要修改clang一些寫死的路徑,請用文字編輯器開啟「C:\GNUstep\msys\1.0\home\username\llvm-tools-clang-lib-Frontend\InitHeaderSearch.cpp」,尋找字串"FIXME: temporary hack: hard-coded paths.",大約在第215行附近的地方,加入底下這幾行。

...
// FIXME: temporary hack: hard-coded paths.
AddPath("C:\\GNUstep\\include", System, true, false, false);
AddPath("C:\\GNUstep\\msys\\1.0\include", System, true, false, false);
AddPath("C:\\GNUstep\\lib\\gcc\\mingw32\\4.6.1\\include", System, true, false, false);
AddPath("C:\\GNUstep\\lib\\gcc\\mingw32\\4.6.1\\include\\c++", System, true, false, false);
AddPath("C:\\GNUstep\\GNUstep\\System\\Library\\Headers", System, true, false, false);
//AddPath("/usr/local/include", System, true, false, false);
break;
....

記得要把原有的AddPath("/usr/local/include", System, true, false, false);拿掉。
 
存檔後,接下來就是要進行編譯了。
$ cd ~/llvm && mkdir build && cd build

$ ../configure --enable-optimized --enable-targets=host-only

$ make

$ make install
第一行切換目錄到llvm底下,並建立一個build目錄,我們將把編譯後的東西放在這個目錄下。
第二行做一些設定。(需要一點時間,看你的機器多快。)
第三行進行編譯。(需要花很多時間,看你的機器多快。) 
第四行進行安裝。雖然會出現groff的錯誤,但沒關係。
 
安裝後,你可以執行
$ clang --version
檢查會不會秀出版本編號。 
clang version 3.1 (trunk 153251)
Target: i686-pc-mingw32
Thread model: posix 

問:接下來,怎麼編譯執行一支hello, world!程式呢?
答:
$ cd ~
$ mkdir hello
$ cd hello
在家目錄下建立一個新目錄hello。我們將放入兩支檔案。
家目錄大概是C:\GNUstep\msys\1.0\home\username,自己找找。

首先是hello.m,用你喜歡的編輯器寫程式,大致內容如下:

#include <Foundation/Foundation.h>

int main(int argc, char * argv[]){
    @autoreleasepool{
        NSLog(@"Objective-C has ARC now, yeah.");
    }
    return 0;
}

另一支檔案是GNUmakefile,內容如下:
include $(GNUSTEP_MAKEFILES)/common.make

TOOL_NAME = hello
hello_OBJC_FILES = hello.m

include $(GNUSTEP_MAKEFILES)/tool.make

然後以這道指令進行編譯與連結:

$ make CC=clang

成功後,執行檔會在hello目錄的子目錄obj裡。

$ ./obj/hello.exe

應該就能看到輸出"Objective-C has ARC now, yeah."了。

恭喜你。

根據我的測試,property與fast enumeration都沒問題。ARC也可以。garbage collection與non-fragile instance variables我沒測試。

問:block呢?
答:需要開啟編譯器選項-fblocks,請修改C:\GNUstep\GNUstep\System\Library\Makefiles\common.make,尋找"INTERNAL_OBJCFLAGS = ",在後面加入"-fblocks"。

這麼一來,底下這支使用block的程式,應該就能成功編譯並執行了。
#import <Foundation/Foundation.h>

int main (int argc, char * argv[])
{
   @autoreleasepool {
      void (^print_message)(void) =
         ^(void) {
             NSLog (@"hello, block.");
          } ;
      printMessage ();
   }
   return 0;
}

問:Objective-C與iOS的學習資源?
答:請看另一篇。


參考文件:
Solarian Programmer's Clang and Objective-C on Windows。

2011/09/14

翻譯:Xcode的建置設定Build Active Architecture Only(Xcode Build Active Architecture Only )by Keith Harrison

文章:Xcode Build Active Architecture Only(Xcode的建置設定Build Active Architecture Only)
日期:2010.04.21,
作者:Keith Harrison
作者的部落格:Use Your Loaf

作者簡介:
任職某IT公司,下班後在iPhone上開發,以及在mac上使用Ruby on Rails。


Xcode的建置設定Build Active Architecture Only

今天在Stackoverflow上看到某個問題,讓我想起在Xcode 3.2.2裡,有些新加入的建置設定,值得在這裡說明一下。隨著iPhone/iPod Touch新型機種推出,以及iPad的加入,你可以決定要將軟體編譯成哪一種處理器架構的格式,下面的設定,都放在target info的標籤Build之下(在target上按滑鼠右鍵然後選Get Info)。

Standard (armv6)

原先的armv6架構,現在以"Standard"字樣出現,產出的二進位檔案,可在所有機種上運行,如果你的軟體還需要在iPhone OS 2.x上跑的話,你應該選擇此設定,因為,根據一些報告指出,2.x的機子跟universal binary二進位檔有點不對頭。

Optimized (armv6 armv7)

若是選"Optimized"的話,這會建置出universal或稱為"fat"的二進位檔,裡面含有armv6與armv7兩套二進位檔,顧名思義,這樣的軟體檔會比較肥大,不過,當放到armv7機種上運作時,就能充分完整地利用處理器的能力。在實務上,使用者到底能不能感受到效能的提升,取決於應用軟體需要處理的事情與運算。如果你的目標對象是OS 3.x或之後的版本,一般來說,你應該選這個項目。

Other (armv7)

如果你的對象只有iPad的話(iPhone OS 3.2),你可以手動把架構設定為armv7,這樣就不會去建置armv6的部份。

Build Active Architecture Only

到目前為止,都很容易理解,但是,有件事要注意。在target的建置設定中,在Architectures那一部分裡有個叫"Build Active Architecture Only"的設定,這會影響二進位檔的建置方式,其預設值是,若是Debug組態,此設定值會被勾選,如下:



Xcode現在會偵測你有連接的機子,根據機型來設定此項目,所以,如果你插入iPod Touch二代的話,Xcode會將active architecture設定為armv6,此時,若你用上面的Debug組態來建置,那麼只會建置出armv6的二進位檔,以節省時間(除非你的專案很大,大到感覺不到,不過,我想你多多少少都能察覺出建置所需的秒數)。

當你新增Distribution組態來發佈軟體到App Store上時,你應該要確認一下,這個選項應該是"不勾選"的狀態,這樣才會建置出肥大的universal binary,如下:



每當蘋果公司推出新機型,建置流程就變得更加複雜,花時間留意一下Xcode裡出現的新選項設定是值得的,即使大家都有共識,Xcode在隱藏細節與複雜設定這一方面,做的還不錯。

2011/07/29

[廣告] 馬上就能用! iPhone SDK 程式碼即可貼

嗨,我朋友翻譯了一本書,在這裡打打廣告。

書名:馬上就能用! iPhone SDK 程式碼即可貼
作者:高山恭介、広部一弥、松浦晃洋
譯者:我朋友負責翻譯,我負責審校程式碼的部份。
出版社:旗標



這是一本iPhone開發超好用的工具書,因為你需要的功能十之八九已經有人寫過了!書中有113招,都是寫好的程式碼,直接用,又快又省時!

市面上有很多 iPhone SDK 程式開發的入門書,這些書都教我們從無到有的學習寫程式,然而,一旦實際開發程式,卻碰到很多需要自己解決的問題──例如「該怎麼鎖住畫面不讓他旋轉」等等...這類問題接連地發生,難道得花時間一一從頭寫起?

本書是以開發過程中常需要的小功能為主題,像是Xcode專案管理的小技巧、Objective-C程式撰寫的訣竅、UIKit使用介面的過場效果與動畫效果、如何處理圖片、音效音樂播放與錄音、硬體版本與功能的判別、網路連線的小訣竅、資料庫SQLite的注意事項、各種外部函式庫的使用等等,這些功能其實已經有人寫過了!你可以隨時拿這些程式碼兜在自己的程式中,而不必自己再花時間找資料研究如何撰寫,大大節省程式開發的時間!

書中內容皆為常見的問題,作者一一整理加以介紹解說,可以省下你大把的寶貴開發時間,這是一本非常有用的好書。


相關連結:
1. 旗標網站關於此書的介紹。
2. 天瓏書局。
3. 博客來、金石堂。

2011/07/23

翻譯:Xcode裡要用哪支編譯器─GCC還是LLVM?(Compiler Options in Xcode - GCC or LLVM? )by Keith Harrison

文章:Compiler Options in Xcode - GCC or LLVM?(Xcode裡要用哪支編譯器─GCC還是LLVM?)
日期:2011.03.21,
作者:Keith Harrison
作者的部落格:Use Your Loaf

作者簡介:
任職某IT公司,下班後在iPhone上開發,以及在mac上使用Ruby on Rails。



Xcode裡要用哪支編譯器─GCC還是LLVM?(Compiler Options in Xcode - GCC or LLVM?)

如果你用的Xcode是3.x版,而且還沒摸過改過專案裡的建置設定,那麼,你用的編譯器大概還是GNU Compiler Collection(GCC)。蘋果公司對GCC所投注的維護人力正緩慢地抽離減少,而且逐步轉移到一套嶄新的編譯器技術上,Low Level Virtual Machine(LLVM),這是一個開放原始碼的專案。築基LLVM之上的開發工具,Xcode 3跟4都有(有些許差異),所以,不必等你過渡到Xcode 4,在那之前就可以開始享受LLVM帶來的好處。

LLVM計畫

所謂的LLVM計畫,是一套開放原始碼的工具組(完整列表請見LLVM.org),建構在一組核心函式庫之上,這組函式庫提供了optimizer(程式碼優化器)與code generator(機械碼產生器),LLVM計畫裡的其他工具還包括,Clang frontend parser(前端語法解析器)與LLDB debugger(除錯器)。Xcode利用了這一套模組化的作法來提供新功能,譬如,加強syntax highlighting(語法加亮、上色)、提供撰碼時常見錯誤的修正建議。

當我寫這篇時,GCC還是Xcode 3裡預設的編譯器,但Xcode 4釋出後,新建專案預設的編譯器改為LLVM-GCC。在這篇裡,我要來檢視一下Xcode 3、4可用的選項。

Xcode裡的編譯器選項(Compiler Options)

在Xcode裡,透過建置設定(build settings)來更改專案(project)或目標(target)的編譯器選項,版本3跟版本4的編譯器選項,有著些許差異,請看:

  • Xcode 3可用的編譯器版本


  • Xcode 4可用的編譯器版本


實務上,我們有三個選擇,看你要繼續用GCC、改用LLVM、或是混著用以取得向後相容性,GCC 4.0就不提了,因為已被揚棄不用了,在Xcode 4裡也看不見了,底下這張圖秀出三種選項的不同處:


各選項背後所代表的意涵有些許差異,看你的Xcode是3還是4,還有,看你是以iOS還是Mac OS X為開發對象。

繼續用GCC老古董(GCC 4.2)

如果你需要,是可以繼續用GCC 4.2,但是,蘋果公司已經發出聲明,他們不會繼續維護修正GCC裡的臭蟲,所以,這不是個長遠的可靠選項。GCC 4.2是Xcode 3裡的預設編譯器,Xcode 4裡還看得見。

LLVM-GCC 4.2

這個選項將兩者混著用,以GCC當frontend parser,把LLVM當後端的optimizer和code generator,這是Xcode 4新建專案的預設編譯器選項,在Xcode 3裡你要自己手動選用。改用LLVM-GCC的主要理由是,它同時具有效能提昇與更快的建置(build)速度,不過,建置時間僅為有限程度的縮短,因為,這個選項仍然以GCC為前端解析器,而且,若你建置的是除錯版(這是你花上大部分時間的地方),它不會啟用optimizer。

LLVM編譯器

這個選項完整使用LLVM的工具組,使用Clang為前端,LLVM為後端的optimizer與code generator,蘋果聲稱,除錯建置時,Clang parser的運行速度是GCC的三倍快,而且還維持著與GCC的相容性,另外,Clang的優點,不僅是速度較快,如果你已經使用過Xcode的Build and Analyze(建置並分析),那你已經見過Clang的威力了,它能夠提供更準確的錯誤與警告訊息,並提供如何修正程式碼的建議。

譬如說,如果你要使用某個之前宣告過的變數,卻打錯字,Clang很聰明,可以找出你真正想要的變數名,並且提出修正建議,然後,在處理後面的程式碼時,它會假設該錯誤已經修正過,這樣一來,會減少無意義的錯誤訊息,你就能輕易地找把心力放在真正發生錯誤的地方,Xcode利用這點,提供Fix-it功能,你會在程式碼裡看到修正建議,點一下就能接受並訂正程式碼:

所以,如果我這麼寫:
NSString *myText;
myTest = [[NSString alloc] init];


Xcode會利用Clang作出如下的訂正提示:



iOS與Mac OS X的差別

較早版本的Xcode僅支援OS X,但從Xcode 3.2.3之後,LLVM編譯器就開始支援iOS與Mac OS X兩個平台;之前Xcode+LLVM不支援C++,不過這項限制我相信已經不存在了,所以,不論你要在iOS或Mac OS X上開發,都可以使用LLVM。

需要注意的限制是,LLDB除錯器僅在Xcode 4上有,目前只支援Mac OS X,如果你開發的是iOS軟體,就沒辦法選擇LLDB除錯器,目前,你只能用GDB。

要選哪個?

那麼,三選項你該選哪個呢?目前我絕對不會用的是,老舊的GCC 4.2,除非你有很強的理由堅持要用,蘋果已經不再維護它了,而且LLVM-GCC看起來更好。在專案中途更改編譯器選項,這可是個大變動,所以,如果你要改,當然要經過審慎完整的測試。

對新的軟體專案而言,LLVM-GCC看起來應該是個安全的選項,蘋果公司認為它夠穩定夠成熟,所以才把它當做Xcode 4的預設選項(你或許不會把穩定成熟這兩個字眼跟Xcode 4本身畫上等號),而且,既然這選項使用的是GCC parser,向後相容性應該沒問題。

我說LLVM-GCC是個安全的選項,但我並不是指Clang/LLVM比較不安全,只是成熟度還沒那麼高罷了,我將一些以前的程式碼拿到Xcode 4上,使用LLVM 2.0編譯器重新編譯,到目前為止還沒發現任何問題,如果你也試過卻問題,我很有興趣聽聽詳細的細節,請留言告知。