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

2010年8月13日 星期五

iPhone initWithFrame: reuseIdentifier: is deprecated解決方法

還有initWithFrame: reuseIdentifier: is deprecated 警告的困擾嗎?
這個問題其實Apple官方的文件有很詳細的解釋.
簡單來說在iOS3.0之後版本都不適用這樣的語法,
修改方式如下:

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIndentifier
      initWithStyle:(UITableViewCellStyle)style 
{
    [super initWithFrame:frame reuseIdentifier:reuseIdentifier];
              initWithStyle:style
    ...
}

這樣重新編譯就不會再顯示警告了:)
參考來源:stackoverflow

iPhone CoreGraphics.framework與UIKit.framework 連結遺失的解決方法

記得前一陣子下載了新版的sdk來幫我的xcode升級,
結果發現自己的project有framework path corrupts的問題.
雖然有幾個framework修一修改一改路徑好像就沒問題了,
可是有兩個非常頑固的framework就是改不好.
雖然兩行紅紅的字有點礙眼,不過能compile的情形下,
我也就睜一隻眼閉一隻眼.

現在project寫的差不多了,想說來看看有什麼地方可以加強一下
就順便來survey一下這問題的解法吧~
網路上不乏這類的問題,卻討論到最後都沒什麼好結果,
看起來在大家更新xcode換上新的sdk版本後,library位置有換.
Apple又不幫使用者自動改過,只好靠自己手動解決啦!

1.  在 "Frameworks" 資料夾上按右鍵

2.  選擇 "Add" --> "Existing Frameworks" --> 點左下角的Add other按鈕
     然後指定framework位置
     /Developer/Platforms/iPhoneOS.platform/Developer/SDKs
     /iPhoneOS3.2.sdk/System/Library/Frameworks/CoreGraphics.framework

     (iOS4.2出來了,路徑請自行調整成iPhoneOS4.2sdk囉;
     另外framework是一整個資料夾都要加進去)
3. 這樣就OK了,UIKit.framework也是在同樣路徑下
    砍掉那紅紅的link,迎接乾乾淨淨的project吧:)

資料來源:koala-studio

2010年8月9日 星期一

iPhone 討厭的背景執行功能!?

呵呵~當所有開發者引頸期盼的iOS正式發佈後
大家似乎對這個 iOS的"多工"特色讚不絕口
例如可以在背景播放音樂 (這算是真正的多工)
或是切換App後,會記住使用者運行到哪一個step
(這算半套的多工...just state freeze)

但是阿~但是~
程式在開發的過程中,如果沒有特別設定的話
用3.2 sdk的xcode編譯出來的程式就會有半套的多工功能喔
這樣一來就很頭痛了
假設今天的程式是需要使用者輸入帳號密碼認證
如果登入完App,又用Home按鈕切換來切換去
一定會發現App會keep登入後的結果
要怎麼拿掉這個我們不想要的功能呢?

方法很簡單
1. 首先開啟專案的info.plist檔案
2. 增加一個key值欄位 UIApplicationExitsOnSuspend
    (或是下拉選單中找Application does not run in background)
3. Bool值設定為YES或是把選項給勾選起來

這樣一來執行程式當中,按下Home按鍵就能真正的離開程式
參考來源:ManiacDev.com

2010年8月6日 星期五

iPhone 常見錯誤百科全書

有鑑於本人健忘的個性
以及撰寫程式時常犯的壞習慣
還是把一些常見的問題記錄下來

使用initWithNibName的物件一定是繼承UIViewController
-[xxxViewController initWithNibName:bundle:]: unrecognized selector sent to instance 0x5d12345
*** Terminating app due to uncaught exception 'NSInvalidArgumentException'

it caused by xxxViewController don't inherit from UIViewController

@interface xxxViewController : UIView UIViewController {
}

舊版xcode sdk3.1.2 專案在4.0底下執行步驟
1. 在載入專案後,會先看到base sdk missing
2. 在專案上面按右鍵-->Get Info


3. 選擇Build標籤,找到Base SDK切換到 iPhone Device 4.0
    (iPhone Device 3.2 會開啟iPad simulator)


4. 然後要編譯之前下拉左上角選單並選擇Simulator


有一個很無言的蠢狀況,希望大家都不要遇到才好
情境:
ViewControllerA想要傳遞一個參數給ViewControllerB
並且程式將由ViewA-->ViewB
ViewControllerA中某個function
{
    ViewControllerB * viewb = [[ViewControllerB alloc]
                               initWithNibName:@"viewcontrollerb"
                               bundle:[Bundle mainBundle]];
    //notice: 下面的動作絕對會做白工,一定要確定controller已經移轉才會正確
    //viewb.TestLabel.text = @"the text will be null";
    //push the controller from A to B
    [self.navigationController pushViewController:viewb animation:YES];

    //notice: pass your data here
    viewb.TestLabel.text = viewa.InputField.text;
}

 有時間我就繼續update吧,不然每一篇的篇幅都太短
 像灌水文章就不好了 :)

2010/09/30 UPDATES:
升級xcode sdk 到4.1 編譯時發現NSErrorFailingURLStringKey會出現Deprecated的警告
查詢一下官方文件: NSError Class
修改成NSURLErrorFailingURLStringErrorKey就好了

2011/04/14 UPDATES:
有了error  message在遇到的時候秀在log裡面確實是不錯啦
只不過好像還少了點什麼...
到底這些error message代表意義是什麼,總不能期待每次遇到了才來處理吧
該去哪裡找這些information 好在處理error時不會有遺漏的呢?
追溯一下 NSURLError.h然後再找到CFNetworkErrors.h這個標頭檔
酷吧~通通都一清二楚囉:)

2011/10/24 UPDATES:
如果出現了modifying layer that is being finalized的錯誤問題
通常就是有重複release UI所導致的
檢查看看並且把[button removeFromSuperview] 置換 [button release]
舉凡UIView都是一樣的處理方式囉~

發現一個MutableArray無法add object,
那應該就要檢查看看是否忘記做初始化的動作.
[[NSMutableArray alloc] init]; 
初始後Array就不會是nil (0x0)自然就能add object了

2010年8月5日 星期四

iPhone Frame v.s Bounds 傻傻分不清楚

寫了好一陣子的xcode 這天突然發現
咦~怎麼我有時候用 frame有時候用 bounds
可是好像看不出來有什麼差別捏...
簡單來說frame是在描述一個super view的座標系統
(在我看來很像一塊畫布canvas,畫家準備要作畫了)

然後bounds是實際在繪圖時的local座標系統
(先比個拍照的手勢,就擷取框框內的部分來畫吧~
 至於畫出來是什麼樣子...就...)

其實Apple的官方文件裡頭就寫的一清二楚囉
不然Standford的課程投影片也有很詳細的講解




下面是外國網友的英文解釋
Frame: Returns the receiver’s frame rectangle, which defines its position in its superview.
Bounds: Returns the receiver’s bounds rectangle, which expresses its location and size 
in its own coordinate system.


本人目前也沒用到什麼複雜的架構,
只要抓住基本精神,座標位置,相對位置,長寬大小資訊就很夠用啦!

2010年8月2日 星期一

iPhone 輸入面板(textfield)的作法

如果不打算從IB裡面去建立textfield,這邊有custom的作法
1. 首先在.h裡先宣告
UITextField *usrname;
@property (nonatomic, retain, readonly) UITextField usrname;
在.m裡面
@synthesize usrname;

2. 然後自己加上

- (UITextField *)usrname
{
  if (usrname == nil)
  {
    CGRect frame = CGRectMake(x, y, width, height);
    usrname = [[UITextField alloc] initWithFrame:frame];

    usrname.borderStyle = UITextBorderStyleNone;
    usrname.textColor = [UIColor blackColor];
    usrname.font = [UIFont systemFontOfSize:17.0];
    usrname.placeholder = @"user name";
    usrname.backgroundColor = [UIColor whiteColor];
    usrname.autocorrectionType = UITextAutocorrectionTypeNo; 
    usrname.autocapitalizationType = UITextAutocapitalizationTypeNone;
    usrname.keyboardType = UIKeyboardTypeDefault;
    usrname.returnKeyType = UIReturnKeyDone;

    usrname.clearButtonMode = UITextFieldViewModeWhileEditing;
    //we can remove it later for recycled cells
    usrname.tag = kViewTag;
    //when the keyboard's "Done" button is pressed
    usrname.delegate = self;
    // Add an accessibility label that describes what the text field is for.
    usrname setAccessibilityLabel:NSLocalizedString(@"username", @"")];
  }
  return usrname;
}


喔~最後要在dealloc中release
[usrname release];
這篇文章也可以在CocoaChina找到

內容回應