2010年12月31日 星期五

iPhone error滿天飛 debug來跨年

有時error往往會在最關鍵的時候冒出來
(譬如說:我想過Christmas,我想去跨年...但是有些bug還沒解)
尤其是一些系統上的問題或是鬼打牆的小細節

首先登場的是
"No provisioned iPhone OS device is connected"

明明就接好好的device,你跟我說沒有provision
要解決這奇怪的現象,
可以試試在Organizer把provisioning裡的files通通delete讓他重裝

接著登場的是
"The program being debugged is not being run"

很無厘頭的error,但是解法跟上面的症狀是一樣的
進入Organizer把provisioning profiles清一清
還不行的話,從apple developer重新下載吧

最後登場的是
"CFPropertyListCreateFromXMLData(): 
Old-style plist parser: missing semicolon in dictionary."

話說在我要提供多國語言需求下,建立了lproj的strings file
奇怪的是出了這個error還跟我說 Unexpected character at line 1
第一行很ok阿,哪有什麼問題!也有semicolon阿
然而在我浪費了約1個小時的青春尋找問題
最後....在文件的很後面 很後面 的某一行.....真的少了一個semicolon...@#$%
所以at line 1是騙人的,semicolon是一定有漏掉的地方
睜大眼睛快找找吧~

Happy New Year & Happy Debugging  lol

2010年12月22日 星期三

iPhone 我後悔了~ performSelector 停下來阿

雖然短的跟一行文沒什麼兩樣
但是之前沒記下來,那就開個版面寫一下

Tips:
故事是這樣發生的...
下面的動作是在touch event觸發之後會去執行的
[self performSelector:@selector(myFunc) 

           withObject:nil 

           afterDelay:delay];

但是,在這個延遲的期間又去觸發touch event...
已經下達的performSelector是不會理會的
使用者可能會有UI行為不一致的感覺

因此,在下達performSelector若能把前一次 未執行完的動作給停掉
會是比較理想的作法,cancel 方法如下:
[NSObject cancelPreviousPerformRequestsWithTarget:self

                                       selector:@selector(hideMsg)

                                           object:nil];


參考來源: stackoverflow
                iphonedevsdk

2010年12月13日 星期一

iPhone 更改專案名稱 (update:完整版)

剛起始一個專案的時候
我有個很糟糕的習慣就是取了爛名字
什麼xxxtest阿,xxxdemo等等...
等真的要release的時候不免被人家念一頓

其實要修改 project name也不難
1. 找到專案的info.plist
2. 找到"Bundle display name"的欄位
3. 將原本 ${PRODUCT_NAME} 改成想要的名稱

如果遇到
the program being debugged is not being run
的error message也不要慌,
shift + command + K 把專案給clean重編就好了

參考資料:stackoverflow
              iphonedevsdk

update: 2011/05/10
嗯~原本的作法算是治標不治本
如果精明一點可以發現透過organizer看到的device log都還是舊名稱
雖然之前就有看到網路上有教學
不過好害怕整個project改爛了就很好笑了

anyway,凡是總有第一次,先備份起來總不會失控吧!
更改專案名稱真的沒有這麼恐怖,給我5分鐘就可以搞定的:)

Let's change the project name completely
1. Copy all files under old project directory to a new one.
    拷貝所有舊專案資料夾底下的file到新的資料夾


2. Rename "old_name.xcodeproj" to "new_name.xcodeproj" then open it.
    將舊的xcodeproj檔名改成想要的新名稱,然後用xcode打開


3. Check if project with the new name under Group&Files pane and Target pane
    修改並確定project name及Targets的名稱是新的


4. Clean the project by shift+command+K and quit xcode that's it, 
    don't rename any other file name at this state.
    清除專案,別急著將其他檔案更名,拜託,我在這步失敗過:P


5. Right click on the "new_name.xcodeproj" and choose "show package content",
    open "project.pbxproj" by xcode.
    回到資料夾在xcodeproj檔案上面按右鍵 選顯示套件內容 打開project.pbxproj


6. Replace all "old_name" with "new_name" save and quit
    用new_name取代所有的old_name, 儲存後離開


7. Open the project again, and rename "old_name" to "new_name" in entire project,
    the red lost referenced files should disappear.
    再次開啟xcode將 project中出現的所有"old_name"用"new_name"取代


8. Open "new_nameViewController.xib" and "MainWindow.xib" to correct the class
     identity.
    開啟"new_nameViewController.xib"與"MainWindow.xib"更改delegate, controller的
    class identity欄位


9. 重新編譯,完成!!

我的作法並無使用console,希望對大家有幫助

參考資料:WebObject blog

iPhone POST url遇上跳脫字元的處理方式

寫過網路程式的人都知道
POST url之前最好要將內容encode過
不然decode過程中一定會有判讀錯誤的問題
ex: user=123&abc&pass=qwe=asd
encode後送出 user=123%26abc&pass=qwe%3Dasd
原本以為下面的encoding method用得好好的
沒想到是一個大bug

[unencodedObj stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];


所以請大家改用

(NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
                                 (CFStringRef)unencodedObj,
                                                    NULL,
                             CFStringRef)@"!*'();:@&=+$,/?%#[]",
                                          kCFStringEncodingUTF8 );


參考來源: simonwoodside
                iphonedevsdk

2010年11月23日 星期二

iPhone UIImage的圓角效果及橫向splash screen

原本以為這兩件事情是有難度的,
還好是自己嚇自己~
參考看看囉:)

UIImage圓角效果
1. 找到左側列表的Frameworks,右鍵加入existing frameworks
QuartzCore.framework

2. 記得在.m的檔案也加入
#import

3. 設定圖片來源的同時也設定圓角效果的屬性
imageView.layer.cornerRadius = 5.0;
imageView.layer.masksToBounds = YES;

//And to add a border:
imageView.layer.borderColor = [UIColor lightGrayColor].CGColor;
imageView.layer.borderWidth = 1.0;
imageView.image = [UIImage imageNamed:@"image.png"];

比較一下有無圓角的效果吧~

載入橫向的splash screen
根據網路上的結論是…辦不到!!
ㄜ~程式上是辦不到,不過圖片可以動手腳
iPhone的Default.png請轉90度,變成320x480
iPad的Default.png請轉90度,變成768x1024


資料來源:
           iPhoneSDKPro
           iphonedevsdk

2010年11月8日 星期一

iPhone can't change language of Xcode

寫程式或許會遇到丈二金剛摸不著頭緒的時候
debug可能會嚐到眼花撩亂頭暈目眩的情形
但是當你碰上Xcode的build setting語言改不掉


一開始會很火大…
阿不就系統設定(system preference)裡面
語言與文字選項(language and text)順序調整一下
再不然,狠一點從list上面移除

再來會很無奈
重開Xcode,登出登入,重開機,無濟於事阿!!!

最後會掉入絕望的深淵
只能看著像是外星來的語言
冒著error,warning無情的嘲弄
猜測屬性的設定,這邊試試看,那邊試試看

不是我歧視日文,而是真的完全看不懂阿
不能這樣溫良恭儉讓下去了~
好不容易我找到了大絕招,這樣做就對了!

1. 首先找到Developer -> Application -> Xcode
2. Ctrl + click -> Show Package Contents -> Resource
3. 把那個叫Japanese.lproj 整個砍了吧!!

重新開啟Xocde,迎接清爽的build setting page吧 :)

資料來源: macosx.com

2010年11月3日 星期三

iPhone 自訂navigation bar全攻略 包含按鈕,高度及圖片背景

iPhone的UI真的有很多小細節,我想也累積一些東西了就po上來吧.
自製化的navigation bar到底有多彈性呢?
我想改變navigation bar上面按鈕的樣式,可以!
想改變navigation bar的高度,可以!
想給navigation bar上個圖片,可以!
那..那navigation bar上按鈕的位置呢? 還是可以!!

如果技巧太鼈三就包涵一下啦:P
navigation bar中的按鈕參照UIBarButtonItemStyle所定義項目少了custom這項
不過可以透過initWithCustomView的方式建立自訂的按鈕
詳細作法如下:
1. 先建立一個UIButton,設定其大小位置以及各狀態對應的圖片,最後還要一個action的指向

UIButton * fooButton = [UIButton buttonWithType:UIButtonTypeCustom];

fooButton.bounds = CGRectMake(0, 0, 40.0, 40.0);

[fooButton setImage:[UIImage imageNamed:@"foo.png"] 

   forState:UIControlStateNormal];

[fooButton addTarget:self 

        action:@selector(fooFired:) 

     forControlEvents:UIControlEventTouchUpInside];

2. 接著new一個UIBarButtonItem後,加入navigationItem(這邊以右邊為例)

UIBarButtonItem *fooBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:fooButton];

 self.navigationItem.rightBarButtonItem = fooBarButtonItem;

 [fooBarButtonItem release];

(trick 1) 接下來講講navigation bar的高度怎麼改變,
網路上可以找到一些方法,不過直接改變高度似乎不可行(至少我自己試過不行)
self.navigationController.navigationBar.frame.size.height
另外一個就正常啦,set自己想要的大小位置

[self.navigationController.navigationBar 
setFrame:CGRectMake(0, 0, self.view.width, height)];

(trick 2) 給navigation bar上個圖片也不會太難
1. 首先new一個UIImageView

UIImageView * banner = [[UIImageView alloc]

initWithFrame:CGRectMake(0, 0, width, height)];

2. 指定這個ImageView載入的圖片

banner.image = [UIImage imageNamed:@"banner.png"];

3. 透過addsubview的方式加進navigation bar(這裡額外指定layer在最底層)

[self.navigationController.navigationBar insertSubview:banner atIndex:0];

 self.navigationController.titleView = banner;  上面這個作法會讓titleView蓋過title的字 (very important)

咳~醜媳婦終究還是要見公婆
改變navigation bar按鈕位置的方法有點投機
如果想要達到下圖的樣子要善用trick1跟trick2

首先在我們改變navigation bar高度的過程中
一定會發現按鈕的位置都偏下,就像下面的圖

沒關係,我們在navigation bar上面放一個高度較高,size較大的圖片蓋過去
如此一來navigation bar上面的按鈕怎麼看都會在中間啦!

順帶一提:
自訂的navigation bar剛開始跑起來都還好端端的,
但是隱藏過後又要顯示時,
按鈕設定全跑了,navigation bar高度也會回復預設值.
後來解決的方法還滿暴力的,
就是要再度顯示之前,再設定一次navigation bar的frame size

[self.navigationController.navigationBar 
setFrame:CGRectMake(0, 0, width, height)];
[self.navigationController setNavigationBarHidden:NO 
                                       animated:NO];

Update:
如果rotate會導致navigation bar上面的button位置跑掉,
表示其高度被設定回預設值,
解決的方法也是在rotate完成後,再設定一次navigation bar的frame size

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {

  //set your frame size here

}

             stackoverflow - BarButtonItem

2010年10月13日 星期三

iPhone/iPad start apps with specific orientation and device detection

好久沒po筆記了,只能說俺的惰性實在是太容易復發了
一般來說iPhone跟iPad一執行程式起來都是直立狀態
(PortraitOrientation)

如果想指定啟動後就是橫著的方向,設定的方式如下:
1. 因為是app一開始執行就要做的動作,
   所以設定也是在一開始的ViewController裡面
    {ProjectName}ViewController.m  -->
    - (BOOL)shouldAutorotateToInterfaceOrientation:
            (UIInterfaceOrientation)interfaceOrientation

2. 修改並指定interfaceOrientation朝左或右
   return YES;
   return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
   or
   return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);

   補充說明一下 return YES的作法:
   device會參考plist中的Supported interface orientations欄位,
   有指定到的方向device會自己做旋轉動作.

   另外,UIInterfaceOrientationLandscape與UIDeviceOrientationLandscape
   的方向是剛好相反的(這特性可以被作為一些判斷依據)

3. 在參考資料的過程中,有這樣的需求是程式在iPhone跟iPad起始的方向要不同
   一樣是在原處動手腳,加上一些判斷式就能夠分辨device種類了.
   BOOL iPad = NO;
#ifdef UI_USER_INTERFACE_IDIOM
   iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#endif
   if (iPad) {
      // 條件成立表示device為iPad,執行環境iOS3.2以上
   } else {
      // 條件不成立有兩種可能1.device是iPhone或iPod
      // 2.執行環境iOS3.2以前版本不支援UI_USER_INTERFACE_IDIOM
   }

有興趣可以看一下UI_USER_INTERFACE_IDIOM在UIDevice.h的定義
目前我執行起來沒有什麼問題~
網路上有很多討論,如果是universal apps又是another story了:)

很開心在網路上開始看到有人site我的文章了耶~
但是可以請好心的註明一下出處嗎?

參考資料: JEFF LAMARCHE's blogger
               UIDevice Class Reference
               Ole Begemann's blogger
               Sangraal at Programbles
               BillyGiggles at iphonedevsdk


2011/01/03 補充:
iOS version detection

既然有偵測device 型號的方法
iOS版本的偵測當然也不能缺席

#ifdef __IPHONE_3_0
// works on >= iOS 3.0
#else
// works on < iOS 3.0
#end



float ver = [[[UIDevice currentDevice] systemVersion] floatValue];
if (ver >= 3.0) {
    // Only executes on version 3 or above.
}
資料來源:stackoverflow

2010年9月21日 星期二

iPhone Live audio streaming using AudioQueue


原本用AVAudioPlayer來播放一些音效感覺很方便,
可是要播放即時的音訊串流就沒輒了.
請見 Technical Q&A QA1634

好吧~那就自立自強捲起袖子… 趕緊google阿!
不過google大神給的答案實在很朦朧,
勉勉強強找到的殘破程式碼也有看沒有懂.

幸好天無絕人之路 :)
Apress出的iPhone cool projects這本書第六章有寫捏,
又有source code可以run,實在"揪甘心"阿.



官方網



















範例程式:下載

如果剛點開範例程式,跟我一樣有頭暈眼花的症狀.
那不用擔心,沒有這麼難,看完下面解釋說不定就懂了.

從架構上來講,一共分成三個部分:

1. AudioPlayer跟AudioRequest可以視作一個大項
    主要負責下達URLrequest,並將收到的data回傳給AudioStream
    另外就是擔任AudioStream的委託(delegate)去使用AudioQueue

2. AudioStream有三件主要的事情
    * 將一收到的data進行parse並得到StreamID
    * 有了StreamID之後會分成 propertyCallback與packetCallback
       先講propertyCallback, 其目的顧名思義就是要辨識Audio的屬性
       就想像成一段資料收進來,需要貼上標籤,註明格式,頻率等等
    * packetCallback會將收進來的stream分成數個packet
       然後請委託(delegate)幫忙執行AudioQueue的程式部分

3. AudioQueue會接受來自委託(delegate)的幾件事情
    * AudioQueueNewOutput會產生一個新的playback audio queue物件
    * AudioQueuePlay會開始播放AudioQueue裡頭的音訊
    * 上述兩項是延續自propertyCallback的部份,在packetCallback這邊
       因為有一整段stream的大小,所以透過AudioQueueAllocateBuffer給定
       適當的buffer size後,使用AudioQueueEnqueueBuffer一直塞buffer
       到audio queue就會播出我們要的串流音訊啦!


NOTE: 2011/01/10
這個範例被我拿來改用之後發現有memory allocation的問題
我原以為是我改壞了 才造成memory allocation不斷飆升的情況
最近花了一點時間修改一下 發現問題就出在AudioQueueAllocateBuffer
這個function不應該在data每次進來都做一次
如果好好看過Apple提供的playback示意圖
AudioQueueAllocateBuffer只會在AudioQueue宣告出來後指定好

講是這樣講啦~
實際測試了一下書中範例給的mp3
neilmix[dot]com[slash]book[slash]etude[dot]mp3
嗯…一切自我感覺良好,沒有問題
換成linear PCM格式的wav source…結果是"大崩壞"!
追了很久發現有一個叫packetDescription的structure資料全都是null,
難怪在memory copy時都會造成crash.

所以精華來啦~
1. 這邊mp3的audio stream是VBR格式,也就是說每個packet大小可能不一,
    因此packetDescription會特別記錄這些資訊.
    linear PCM的wav是CBR格式自然沒有這些資料,
    所以簡單的方法就是把packetDescriptions copy這段註解掉.

1
2
3
4
5
memcpy(outBufferRef-&gt;mAudioData, data.bytes, data.length);
outBufferRef-&gt;mAudioDataByteSize = data.length;
//memcpy(outBufferRef-&gt;mPacketDescriptions, packetDescriptions, 
  sizeof(AudioStreamPacketDescription) * packetCount); 
outBufferRef-&gt;mPacketDescriptionCount = packetCount;


2. 由於CBR格式中的bit rate是固定關係, AudioQueueEnqueueBuffer後兩個
    參數為0,跟NULL.

3. 總結來講,AudioQueue service是精隨.只要搞清楚流程,一邊餵進Audio基本資料
    另一邊allocate好audio queue把data依序塞進去,輕鬆播放串流音訊非難事!

參考資料: iOS Reference Library
                zonble
                cocoaChina
                stackoverflow (synthesize with CoreAudio)
                stackoverflow (iPhone combine audio files)    

歐~差點忘了,
在iOS4的simulator環境下跑,開始的時候都會頓一下
log會出現"AddRunningClient starting device on non-zero client count"訊息
雖然不會造成什麼大問題,不過這樣卡卡真的有點討厭就是了
網路上一片無解阿~討論串

2010年9月20日 星期一

iPhone get rid of UIColor

還在用UIColor嗎?嫌系統顏色不夠豐富嗎?
如果想使用hex value來自定色彩
網路上都有提供簡單作法:

1. 把下面整段marco複製到最前頭,define好RGB的範圍
#define UIColorFromRGB(rgbValue) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

2. 之後就有UIColorFromRGB()這個method可以用.例如:
[aButton setTitleColor:UIColorFromRGB(0x999999
              forState:UIControlStateNormal];

3. 就這樣,很簡單的~

   參考資料:iPhone Dev SDK
                 eric e. dolecki

2010年9月13日 星期一

iPhone 使用NSLog來顯示各種型態資料

我在xcode的開發過程中,
除了使用build and debug mode來逐一檢查參數的值
有時候也需要在build and run mode底下留一些訊息,
這時候一定會用到NSLog.
可是使用上若是沒注意資料型態,胡亂指定可是會導致crash的,
因為邪惡的compiler在編譯過程中根本不會有錯誤阿!

所以這邊筆記一下常用的資料型態取法
NSLog(@"%@",myobj);

%@         object
%d, %i     signed int
%u         unsigned int
%f         float/double

%x, %X    hexadecimal int
%o         octal int
%zu        size_t
%p         pointer
%e         float/double (in scientific notation)
%g         float/double (as %f or %e, depending on value)
%s         C string (bytes)
%S         C string (unichar)
%.*s       Pascal string 
(requires two arguments, pass pstr[0] as the first, 
pstr+1 as the second)

%c         character
%C         unichar

%lld       long long
%llu       unsigned long long
%Lf        long double

資料來源: cocoadev
               cocoachina

這篇出自cocoachina的精華文章更清楚喔

2010.12.08  補充顯示boolean參數方法
1
NSLog(@"Bool object is: %@ ",(boolobj ? @"YES" : @"NO"));

2011.10.21 補充顯示CGPoint的方法
1
NSLog(@"The point is: %@ ",NSStringFromCGPoint(point));

2010年9月7日 星期二

iPhone Executing Code in the Background (上)

為了徹底搞清楚iOS提供的多工有什麼規範
我居然很認真的看了官方的一些資料,還筆記起來
想說都筆記了,就分享一下,也歡迎大家多多指教
Executing Code in the Background


大部分的程式只要一進入background就會被suspend住而且不執行任何code。
除非我們特別去notify系統,蘋果有提供幾個option讓不同種類的行為在背景下執行。

application準備在background執行
1. application會先link against iOS4 
2. 接著在假定支援多工的情形下會自動implement 合適的method來處理轉換到背景
     的這件事情

application檢查到底有沒有支援多工
首先,程式有背景執行工作的特性不見得都能被iOS的device所支援
又如果,device根本就不支援背景執行工作或不是搭配iOS4及之後的版本,
那系統會用最早先的方式來處理我們的application.
具體來說,當我們的app要離開時,app會被終止並從memory中清掉,然後app的delegate會收到 applicationWillTerminate:的訊息

反正app在不支援多工的情形下應該要有所準備.
如果我們的code想要有支援背景工作但不去執行這部份,
可以用 UIDevice class中 multitaskingSupported的屬性來檢查到底有沒有支援多工.
如果app是要支援iOS4之前的系統那更要在執行背景工作前check這項屬性

Checking for background support on earlier version of iOS
UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
   backgroundSupported = device.multitaskingSupported;

先宣告我們支援哪些背景工作
要支援一些類型的背景工作就必須在app執行前先宣告好.
app使用Info.plist中UIBackgroundModes的鍵值來宣告這類的事情,
這些鍵值的內容是包含了一個或以上的array,例如:

audio: app 可以在背景播放有聲內容.
location: app 可以讓使用者知道自己的所在位置.
voip: app 可以讓使用者使用internet 來打電話.

上述的這些value可以讓app知道什麼時間點該起來回應相對的事件.
然後iOS提供了兩種背景工作的方式

- app 可以要求系統提供一個extra的時間給這項工作
- app 預先排好要被傳遞的local notification時間點

背景狀態轉換的支援
基本上來講只要app是使用iOS4或更新的版本都會支援背景狀態的轉換
如果要很完整的support,或是說用比較嚴謹且正確的方式來支援
則需要確保在delegate中有實作下面幾個methods:

上述這些methods都是在app執行當中即時告知我們app將要轉換狀態了
雖然說有些method早在專案建立之初就已經有實作了,
只是這邊需要增加一些行為判斷來確保背景執行起來是很安全的.
例如: 當一個進入背景並且從記憶體被清除的app重新被launch起來時
我們可能會希望可以繼續之前離開時的狀態.
這個method來檢查有沒有額外的information或是其他已儲存的參數需要在app被喚起後把它restore回app的ui

成為多工感知且可靠的Application
在背景當中執行app一定是比前景中執行要來的限制多多,即使app沒有要在背景執行,
官方也建議了以下的原則:
  • Do not make any OpenGL ES calls from your code.
  • 只要createEAGLContext的物件或是牽涉到任何有關 OpenGL ES的drawing指令會讓app馬上被終止掉.
  • Cancel any Bonjour-related services before being suspended.
  • 當我們的app要移到背景但還沒被suspend之前,應該要在Bonjour那邊取消註冊並且關閉所有與網路服務有關的listing sockets.再說,一個被suspend的程式也不能對incoming 的服務要求有所回應.所以為了避免出現占著茅坑不拉屎的狀況出現,如果不在suspend之前自己關閉所有Bonjour服務,系統還是會自動幫我們關掉的.
  • Be prepared to handle connection failures in your network-based sockets.
  • 系統可能會在一些原因下將socket與我們的app拆開來.只要我們socket-based的程式有為一些類型的網路failure做準備,像是:lost signal或是網路轉換就不會導致任何不正常的問題.當我們要返回程式時使用socket遇到失敗可以很簡單的重新建立連線來解決.
  • Save your application state before moving to the background.
  • 在記憶體不足的情況下,背景執行中的程式會從記憶體中被清掉.被suspend的程式首當其衝,而且系統不會有任何的提示.所以app應該在進入背景執行前要備妥充足的資訊,記錄,參數好讓需要的時候可以重新組回來.在回復app的同時會讓使用者看到app主畫面重啟時的snapshot可以增加一致性.
  • Release any unneeded memory when moving to the background.
  • 當然背景執行的程式需要有充足的狀態訊息來達到快速重返前景執行的目的.但是有物件或是滿大的記憶體空間都沒有要再使用(例如沒用到的圖檔)就應該考慮在進入背景執行前把他們都release掉
  • Stop using shared system resources before being suspended.
  • 如果app有用到系統分享出來的資源(例如AddressBook),要在被suspend之前停止使用.這些系統分享出來的資源優先權會落到前景中的app,如果捨不得放掉這些資源系統還是會強迫中斷的.
  • Avoid updating your windows and views.
  • 雖然說在app背景執行中一直去操縱或是增加window,view object不會導致程式被終止.但是這類的事情應該要延後到app又重回前景再來處理.畢竟在背景的程式是看不到畫面,一直update是update心酸的嗎
  • Respond to connect and disconnect notifications for external accessories.
  • 如果app與外部的附件有communication,系統會自動發出斷線的通知給要進入背景的app.而app應該要註冊這個通知好用來關閉與外部附件的session.當app重回前景時也會藉由註冊的通知來給予重新連線的機會
  • Clean up resources for active alerts when moving to the background.
  • 為了在切換app間保留內文,系統並不會在app進入背景執行時自動關掉action sheet(UIActionSheet)或是alert view(UIAlertView).
  • 但app使用的是iOS 3.x或之前版本, alert view與action sheet仍會被關掉,所以app的cancellation handler就有機會在那邊執行了.這時開發者可以自己決定是要在進入背景執行前提供一個合適的清除行為(手動去cancel那些action sheet或是alert view)還是要把內文資訊給存下來,之後再回復那個view.(萬一在app被終止掉的狀況下)
  • Remove sensitive information from views before moving to the background.
  • 在app要進入背景執行前,系統會給app當下的window做一個快照,當app又要回復時會秀這個快照一下下.因此從applicationDidEnterBackground:這個method回復之前,我們因該針對敏感的使用者私人訊息加以隱藏或覆蓋.
  • Do minimal work while running in the background.
  • 在背景工作能執行的時間要比前景有更多的限制.如果我們的app在背景播放音樂或是在監控location的變化,那就要focus在重點上並把較不重要的事情挪後處理.app若是在背景中花很多時間在執行一些事情,系統會縮短給app的時間甚至通通給終止掉.

還有~等我又發瘋把它們認真看完吧...

    2010年8月25日 星期三

    iPhone How to load a local HTML file and its images?

    今天我需要從local加入一個html
    而html又是附在各個不同語言的lproj資料夾下

    現在有個抉擇來啦~
    1. 是要各語言資料夾下都包含一份圖檔
    2. 還是要共用一份resource就好了呢?
    嗯~選1的話,還滿直覺的,當下不用什麼煩惱
    但是未來要改個圖改個名可是要很辛苦的一份一份改捏
    而且明明就可以共用的resource又何必複製好多份呢

    好吧,所以我有一個資料夾完全是拿來放image resource
    那UIWebView 這邊一開始我選擇loadRequest的method來做
    不過圖片都是叉燒包...

    很明顯我load html的路徑跟image是不同位置,當然行不通囉
    嗯~換個邊思考一下,我們把url指到image那邊吧
    看起來 loadHTMLString: baseURL: 這個method可以滿足我們的需求

    1. 我們除了將html以iPhone常用的UTF8進行編碼,並且指定html的路徑
        (程式碼line 5,6,8,9,10)

    2. image path要特別處理過才能在UIWebView下正常運作
        (程式碼line1,2,3)

    3. 試試看吧~ it works like a charm!


    NSString *imagePath = [[NSBundle mainBundle] resourcePath];
    imagePath = [imagePath stringByReplacingOccurrencesOfString:@"/" withString:@"//"];
    imagePath = [imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
    NSString* filePath = [[NSBundle mainBundle] pathForResource:@"test" 
       ofType:@"html"];  

    [webView loadHTMLString:[NSString stringWithContentsOfFile:filePath
                                             encoding:NSUTF8StringEncoding 
                                                         error:nil
                 baseURL:[NSURL URLWithString: 
                      [NSString stringWithFormat:@"file:/%@//",imagePath]]];

    參考資料:dBlog
                  iphoneincubator
                  brainwashinc
                  第24個夏天後

    2010年8月24日 星期二

    iPhone 讓程式能夠有setting頁面

    大部分的社群app都會有一個頁面
    可以提供使用者設定資料,操作方式
    而這個頁面通常都是跟app本身分開
    由settings的按鈕進入






    進入後的頁面大概就長這個樣


















    實作的方法也算簡單,按部就班不容易出錯

    1. 在專案中新增一個file,我加在Resource資料夾下
        (new file --> Resouce --> Settings Bundle)















    2. 名字取好按下finish 會發現list中多出了白色積木的bundle file
        點開階層則包含了Root.plist和語系檔
        這時候點一下Root.plist, plist內容會顯示在右側













    3. 密密麻麻的表格其實並不複雜
        仔細看一下其實還是有規律可循的
        首先,我們範例中有三大區塊
        - Provision settings
        - User settings
        - General

        瞧~所以我們的item0,item2,item5格式就是
        PSGroupSpecifier 跟 Title name兩個String的組成

        item1 是一個PSMultiValueSpecifier的類型

        item3 item4是PSTextFieldSpecifier的類型
        底下可以設定Title,KeyboardType,IsSecure等參數

        item6則是PSTitleValueSpecifier的類型
        可以透過DefaultValue的參數來設定cell裡面的內容
        喔~對了,這種類型的cell是不可點選的
      
        如果還有其他類型的cell,可以參考這個教學:iphonesdkarticles

    內容回應