2010年6月28日 星期一

UIImageWriteToSavedPhotosAlbum Domain=ALAssetsLibraryErrorDomain Code=-3301 "寫入忙碌中"

前陣子在 iPhone 模擬器上寫之儲存照片的小程式,使用連續儲存的方式,發現可以很順利,但是移到實體機子上頭,卻發現儲存的照片張數不對,假設有 10 張照片要儲存,但真正存進去的只有 5 張不到,而且現象是有時張數多有時張數少,但一定沒有達到 10 張。


後來透過 error report 並在實體機上跑時才看到錯誤訊息:


Error Domain=ALAssetsLibraryErrorDomain Code=-3301 "寫入忙碌中" UserInfo=0xXXXXXX {NSLocalizedFailureReason=, NSLocalizedRecoverySuggestion=再試著寫入一次, NSLocalizedDescription=寫入忙碌中}


偶爾也還有看到 sqlite3 等訊息(但它有容錯處理)


sqlite error 5 [database is locked]
sqlite prepare statement retry was successful.  Continuing.


而真正的問題還是儲存照片問題,最後則是想到用 sleep 的方式解決,也就是避開短時間儲存,改成每存完一張 sleep 1.5 秒


- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error
contextInfo:(void *)contextInfo
{
        if( error != nil )
               
NSLog( @"SaveError(%f,%f) Message:%@", image.size.width,
image.size.height, error);
}

- (void)saveToPhotoLibrary
{
    for( id raw_data in [images allValues] )
    {
        UIImage *image = [[UIImage alloc] initWithData:raw_data];
        UIImageWriteToSavedPhotosAlbum( image, self, @selector(image:didFin    ishSavingWithError:contextInfo:), nil );
        [image release];
        [NSThread sleepForTimeInterval:1.5];
    }
}


修正後,還是偶爾會出現其他的訊息,並且隨著 Photos Library 內的圖片增加,導致訊息顯示會越來越頻繁甚至不正常當掉(當掉可能比較跟記憶體控制有關)


slow transaction: time was 0.xxxxxx seconds
Received memory warning. Level=1
Received memory warning. Level=2


暫時還沒想到恰當的解法(可以考慮依 Photos Library 的照片張數調整 sleep 秒數),未來設計上可能還是要避開把資料塞進 Photos Library 吧!


2010年6月27日 星期日

iOS 開發教學 - 讓 App 支援多國語言、依語言顯示 App 名稱

LocalizableString

iTunes App Store 可在於多個國家販售、散佈分享所寫的 App,因此,客製化不同語言的操作介面是很基本的功夫,概念上很簡單,凡是在 App 上使用 NSString 印出來的字串,都可以透過查表的方式,依照設定的語言,更改成想要的。

如:

UILabel *show = [[UILabel alloc] init];
show.textLabel.text = @"Hello Moto";

希望可以依照語言改變時,那就改用 NSLocalizedString 處理:

UILabel *show = [[UILabel alloc] init];

show.textLabel.text = NSLocalizedString( @"Hello Moto" , @"note" );

其中後面的 @"note" 也可以空白,那類似註解、用來回憶的,但如果要顯示的文字已經很有記憶性跟意義性,那其實後面就乾脆留白就好囉。透過上述的使用,如果沒有建立甚麼查表,那其實 show.textLabel.text = NSLocalizedString( @"Hello Moto" ,
@"note" ); 等同於
show.textLabel.text = @"Hello Moto"; 這樣的效果,也就是可以把一堆常用輸出的部分改成 NSLocalizedString 也不會怎樣。

接著建立查表,在此僅提供簡單的 source code 轉換的部分,關於使用 Interface Builder 也可以透過 Xcode 介面產出,只是我沒再用啦,所以也忘了。

$ cd YourProject ;
$ mkdir English.lproj ;
$ genstrings -o English.lproj/ iPhone/*.m iPhone/*.h iPad/*.m iPad/*.h *.m *.h

透過上述三步,就將 YourProject 裡頭所有的 *.m 和 *.h 裡頭用到的 NSLocalizedString 部份,拉出來見出可以查詢的表格,並儲存在 YourProject/English.lproj/ 中,其內文:

/* No comment provided by engineer. */
"Hello Moto" = "Hello Moto";

這等同於 Key-Value Pair 的模式,因此,如果你希望在繁體中文顯是為"你好機車",那對應則改成:

/* No comment provided by engineer. */

"Hello Moto" = "你好機車";

以上是簡短的範例。真正的使用的過程,一開始是使用 genstrings 產生出 Localizable.strings 檔案,接著把他拖拉進去 Project 中,這時彈跳的視窗記得要選成 UTF-16 ,而當你想要新增另一個語言時,則是對 Localizable.strings 點選右鍵挑選 Get Info,彈跳的視窗下面則可以直接按 Add Localization ,接著可以打入語言,如 zh_TW 、 zh_CN 等

utf16

Add Localization

如此一來,在 Localizable.strings 下則會自動幫你複製一份 zh_TW 出來,而 Project 目錄下也會自動產生 zh_TW.lproj 目錄。接著一樣的用法,只是變成在 zh_TW 語言時,想要顯示的字是甚麼。而 App 預設的語言是 English ,可以在 Project-Info.plist 中 Localization native development region 項目裡看到這個設定值。

經過上述的設定,你的程式就可以依照設備的語言,顯示內容囉,然而,還有一種設定,那就應用程式在設備上顯示的名稱,此部分則是另外在建立一個檔案 InfoPlist.strings 並且拉到 Project 裡頭,一樣挑選 UTF-16 ,其內文:

CFBundleName = "HelloMoto";  
CFBundleDisplayName = "HelloMoto";

一樣可以透過對 InfoPlist.strings 進行 Get Info 和 Add Localization 來建立其他語言的顯示。

木偶人動畫電影版"BBS鄉民的正義"預告片





 


第一次是看鐵拳無敵孫中山,這次預告片拍得很讚!看到這些影片,都讓人想起 BBS 對台灣人的影響,有的人覺得那邊只不過是個純文字的瀏覽介面,再不然頂多加個 ASCII 圖片,或更進階成一秒秒切換成的動畫等等,除此之外,還有人設計相關的程式互動,讓你玩遊戲甚至在上頭寫寫程式等等的。但重要的並不是這些,因介面的簡單,少了許多像網站的廣告;因 telnet 協定,讓切換頁面用的資源更少更快;最重要的,裡頭的鄉民、文章、板規、站規不就等同於一個小型社會嗎?人才是最珍貴的價值,以 PTT 來說,技術上已經允許同時上線人數突破 15 萬關卡了!像最近的世足賽,其 WorldCup 可以同時超過一萬人的板友互動哩,當然,還有記者最愛挖新聞的八卦板,幾乎每次看都一定有上千人在裡頭。


前陣子高中的 BBS 站復站了,回憶起 1999 年的時光,過了十年後,到底還需不需要 BBS 呢?我想,這早就已是另一種台灣的文化了。有人再探討需要或去除哪些文化嗎?一切就讓他靜靜地翻騰吧


更多資訊請上 木偶人動畫專區


 






























99交通大學畢業 MV








很讚的 MV ,就算畢業了三年,很多場景就像昨天一般,瞬地轉入了眼簾。


2010年6月23日 星期三

[C] strtok , strtok_r 和 strtok_s

我好像還沒有真正用過 strtok,一開始還有點慌,擔心東擔心西的,用了才知道還滿順的,順便筆記一下,另外,若是要在 vistual studio 系列上,可以把 strtok_r 直接 define 成 strtok_s 就可以,細節請參考 msdn


程式碼:


#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main( int argc, char *argv[])
{
        char  *getTag, *tokenBrk, *data;
        char *tag[100];
        int cnt=0;

        data = NULL;

        if( argc > 1 )
                data = argv[1];
        else
                data = NULL;

        for ( getTag = strtok_r( data , ", " , &tokenBrk ) ; getTag ; getTag = strtok_r( NULL , ", " , &tokenBrk ) )
        {
                tag[cnt++] = getTag;
                //printf("[%s]\n" , getTag );
        }
        printf("[Src:%s]\n" , data );

        while( cnt-- > 0 )
                printf("[%s]\n" , tag[cnt] );

        return 0;
}


結果:


> ./a.out " 1 2 , 3,45 ,678 , 90 , ,"
[Src: 1]
[90]
[678]
[45]
[3]
[2]
[1]


原先一直很好奇為啥 getTag 取出來的字串有 '\0' 結尾,後來就把原字串印出來就知道了,因為那些 ',' 或 ' ' 都被取代掉囉!