顯示具有 objective C 標籤的文章。 顯示所有文章
顯示具有 objective C 標籤的文章。 顯示所有文章

2012年9月4日 星期二

iOS 應用程式的沙箱機制


在操作的過程中經常需要取得目前應用程式的資料夾路徑,接下來就簡略地介紹 iOS 的應用程式沙箱機制,以及如何取得沙箱中的資料夾路徑。
在 iOS 系統中,出自於安全性的前提下,應用程式採用了沙箱 (Sandbox) 安全體系的運作機制,當應用程式被安裝到 iOS 系統時,系統會替應用程式建立一個主目錄 (Home Directory),以應用程式的 GUID 來命名,這個主目錄便是應用程式本身的 Sandbox,應用程式被限制僅能存取自己的 Sandbox,無法任意地使用其他應用程式 Sandbox 中的資料,如有需要時必須發送數據請求並經過權限的檢測認可,無法通過檢測則請求會被中斷。

沙箱 (Sandbox) 機制的幾項特點

  • 每個應用程式都有屬於自己的儲存空間
  • 應用程式無法存取其他應用程式的儲存空間
  • 應用程式送出的請求數據必須通過權限的檢測,若無法通過時則請求會被中斷。

沙箱結構

一般而言,沙箱中會有下列四個子資料夾:
²  AppName.app
應用程式主目錄,所有與應用程式建置時有關的檔案都存放於此資料夾中,包括應用程式本身的執行檔及相關資源等等,僅允許讀取不可修改。又稱應用程式的程式包。由於應用程式在安裝時必須經過簽名認證,所以在運行時不能對這個資料夾中進行任何內容的修改動作。
²  Documents 
這個資料夾用來儲存使用者的資料或其他應定期備份的資料,因此在應用程式運行時需要使用的檔案都應該被儲存於這個資料夾中
²  Library
此資料夾中包含兩個子目錄,分別是:
Ø   Caches 
用來儲存應用程式專用的文件,例如保存應用程式再次啟動時需要的快取資料
Ø   Preference 
儲存應用程序的偏好設置文件,應用程式不應該直接於此資料夾創建偏好設定文件,而是透過 NSUserDefault 類別來取得與進行偏好設定文件的操作
²  tmp 
用來儲放臨時檔案的資料夾,保存應用程式再次啟動時較不需要的快取資料。當 iOS 裝置與 iTuens 進行同步時,iTunes 不會將存放於 tmp 資料夾中的檔案進行備份。
若是應用程式中使用了 tmp 資料夾做些檔案的暫存動作,務必記得自行清除不再使用的檔案,避免 tmp 資料夾中的垃圾檔案佔據了使用者的儲存空間。

如何取得沙箱中的資料夾路徑

前面已經簡單地介紹完 iOS 沙箱機制,接下來的重點便是我們要如何去取得沙箱中的資料夾路徑,畢竟操作檔案文件前的先決條件是我們必須得知道檔案路徑在哪裡,才有辦法進行後續的存取動作。
    // 取得應用程式根目錄資料夾路徑
    NSString *homeDirectory = NSHomeDirectory();

    // 取得 AppName.app 程式包路徑
    // - 直接從 Info.plist 屬性清單中 "NSBundleInitialPath" 鍵值直接取得應用程式的程式包路徑
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];     // 取得 Info.plist 屬性清單
    NSString *appFilePath = [infoDictionary objectForKey:@"NSBundleInitialPath"];

    // 取得 Documents 資料夾路徑
    NSString *documentsDirectory = [homeDirectory stringByAppendingPathComponent:@"Documents"];

    // 取得 Library 資料夾路徑
    NSString *libraryDirectory = [homeDirectory stringByAppendingPathComponent:@"Library"];

    // 取得 Caches 與 Preference 資料夾路徑
    NSString *cachesDirectory = [libraryDirectory stringByAppendingPathComponent:@"Caches"];
    NSString *preferenceDirectory = [libraryDirectory stringByAppendingPathComponent:@"Preference"];

    // 取得 tmp 資料夾路徑
    NSString *tmpDirectory = [homeDirectory stringByAppendingPathComponent:@"tmp"];

2012年8月10日 星期五

UIViewController的生命週期 - Part2



資料來源:

UIViewController的生命週期及iOS程式執行順序



當一個視圖控制器被創建,並在螢幕上顯示的時候。 代碼的執行順序


alloc
創建對象,分配空間
init (initWithNibName)
初始化物件,初始化資料
loadView
nib載入視圖 ,通常這一步不需要去干涉。除非你沒有使用xib檔創建視圖
viewDidLoad
載入完成,可以進行自訂資料以及動態創建其他控制項
viewWillAppear
視圖將出現在螢幕之前,馬上這個視圖就會被展現在螢幕上了
viewDidAppear
視圖已在螢幕上渲染完成

當一個視圖被移除螢幕並且銷毀的時候的執行順序,這個順序差不多和上面的相反


viewWillDisappear
視圖將被從螢幕上移除之前執行
viewDidDisappear
視圖已經被從螢幕上移除,使用者看不到這個視圖了
dealloc
視圖被銷毀,此處需要對你在initviewDidLoad中創建的物件進行釋放

關於viewDidUnload :在發生記憶體警告的時候如果本視圖不是當前螢幕上正在顯示的視圖的話 viewDidUnload將會被執行,本視圖的所有子視圖將被銷毀,以釋放記憶體,此時開發者需要手動對viewLoadviewDidLoad中創建的物件釋放記憶體。 因為當這個視圖再次顯示在螢幕上的時候,viewLoadviewDidLoad 再次被調用,以便再次構造視圖。
 當我們創建一個UIViewController類的物件時,通常系統會生成幾個預設的方法,這些方法大多與視圖的調用有關,但是在視圖調用時,這些方法的調用順序如何,需要整理下。
 通常上述方法包括如下幾種,這些方法都是UIViewController類的方法:

- (void)viewDidLoad

- (void)viewDidUnload

- (void)viewWillAppear:(BOOL)animated

- (void)viewDidAppear:(BOOL)animated

- (void)viewWillDisappear:(BOOL)animated

- (void)viewDidDisappear:(BOOL)animated



下面介紹下APP在運行時的調用順序。

1- (void)viewDidLoad

      一個APP在載入時會先通過調用loadView方法或者載入IB中創建的初始介面的方法,將視圖載入到記憶體中。然後會調用viewDidLoad方法來進行進一步的設置。通常,我們對於各種初始資料的載入,初始設定等很多內容,都會在這個方法中實現,所以這個方法是一個很常用,很重要的方法。

      但是要注意,這個方法只會在APP剛開始載入的時候調用一次,以後都不會再調用它了,所以只能用來做初始設置。

2) - (void)viewDidUnload;

      在記憶體足夠的情況下,軟體的視圖通常會一直保存在記憶體中,但是如果記憶體不夠,一些沒有正在顯示的viewcontroller就會收到記憶體不夠的警告,然後就會釋放自己擁有的視圖,以達到釋放記憶體的目的。但是系統只會釋放記憶體,並不會釋放物件的所有權,所以通常我們需要在這裡將不需要在記憶體中保留的物件釋放所有權,也就是將其指針置為nil

      這個方法通常並不會在視圖變換的時候被調用,而只會在系統退出或者收到記憶體警告的時候才會被調用。但是由於我們需要保證在收到記憶體警告的時候能夠對其作出反應,所以這個方法通常我們都需要去實現。

      另外,即使在設備上按了Home鍵之後,系統也不一定會調用這個方法,因為IOS4之後,系統允許將APP在後臺掛起,並將其繼續滯留在記憶體中,因此,viewcontroller並不會調用這個方法來清除記憶體。

3- (void)viewWillAppear:(BOOL)animated;

      系統在載入所有資料後,將會在螢幕上顯示視圖,這時會先調用這個方法。通常我們會利用這個方法,對即將顯示的視圖做進一步的設置。例如,我們可以利用這個方法來設置設備不同方向時該如何顯示。

      另外一方面,APP有多個視圖時,在視圖間切換時,並不會再次載入viewDidLoad方法,所以如果在調入視圖時,需要對資料做更新,就只能在這個方法內實現了。所以這個方法也非常常用。

4) - (void)viewDidAppear:(BOOL)animated

      有時候,由於一些特殊的原因,我們不能在viewWillApper方法裡,對視圖進行更新。那麼可以重寫這個方法,在這裡對正在顯示的視圖進行進一步的設置。

5) - (void)viewWillDisappear:(BOOL)animated

      在視圖變換時,當前視圖在即將被移除、或者被覆蓋時,會調用這個方法進行一些善後的處理和設置。

      由於在IOS4之後,系統允許將APP在後臺掛起,所以在按了Home鍵之後,系統並不會調用這個方法,因為就這個APP本身而言,APP顯示的view,仍是掛起時候的view,所以並不會調用這個方法。

6) - (void)viewDidDisappear:(BOOL)animated

      我們可以重寫這個方法,對已經消失,或者被覆蓋,或者已經隱藏了的視圖做一些其他操作。


IOS 開發 loadView viewDidLoad 的區別


iPhone開發必不可少的要用到這兩個方法。 他們都可以用來在視圖載入的時候,初始化一些內容。 但是他們有什麼區別呢?

viewDidLoad 此方法只有當viewnib檔初始化的時候才被調用。

loadView 此方法在控制器的viewnil的時候被調用。 此方法用於以程式設計的方式創建view的時候用到。 如:

1.
 2.- ( void ) loadView {
 3.    UIView *view = [ [ UIView alloc] initWithFrame:[ UIScreen
 4.mainScreen] .applicationFrame] ;
 5.    [ view setBackgroundColor:_color] ;
 6.    self.view = view;
 7.    [ view release] ;
 8.}
 9.

你在控制器中實現了loadView方法,那麼你可能會在應用運行的某個時候被記憶體管理控制調用。 如果設備記憶體不足的時候, view 控制器會收到didReceiveMemoryWarning的消息。 默認的實現是檢查當前控制器的view是否在使用。如果它的view不在當前正在使用的view hierarchy裡面,且你的控制器實現了loadView方法,那麼這個view將被release, loadView方法將被再次調用來創建一個新的view



 .

UIViewController的生命週期 - Part1



資料來源:http://w11h22j33.iteye.com/blog/1565210

         UIViewControl是IOS程式中的一個重要組成部分,扮演者一個大管家的身份,管理著程式中的眾多視圖,今天看看了官方文檔並做了如下一些簡單的記錄:

        何時載入view,載入的原則是什麼,視圖何時消失等問題,文檔中講的都很詳細。Controller的view最好在需要顯示時再去載入,並且在系統發出記憶體警告時釋放比必要的view及相關的資料物件。

一、UIViewController的初始化

  初始化時會根據需要調用init,initWithCoder等相關函數,這個時候我們可以做一下簡單的初始化操作,建立ViewController中需要使用的資料模型等,不建議在初始化階段就直接創建view及其他與顯示有關的物件(應該放到loadView的時候去創建,或者採用懶載入的方法創建)。
  我們都知道ViewController可以通過代碼和xib兩種方式創建,這兩種方式的初始化流程也不盡相同。

  1)使用xib創建的VC

  xib其實最終是會把我們的設置保存成一個資料集,當需要初始化構建VC的時候,回去讀取記錄的資料集,然後幫我們動態的創建VC,因此可以想像它在初始化時會先去找看是否實現initWithCoder方法,如果該類實現了該方法,就直接調用initWithCoder方法創建物件,如果沒有實現的話就調用init方法。調用完初始化方法以後緊接著會調用awakeFromNib方法,在這個方法裡面我們可以做進一步的初始化操作。

  2)使用代碼創建VC

  使用代碼創建時,我們根據需要手動的創建VC中的資料,如果自己定制VC時,還需要在init中調用[super init]。

二、UIViewController中View的load和unload

  前面講了不建議在VC初始化的時候就創建view及其他與顯示相關的代碼,官方文檔建議將View的初始化操作放到loadView的時候再做,當VC接到記憶體告警時會調用didRecieveMemoryWarning這個時候我們就要做出回應,釋放暫時不需要的物件。如果無視這個警告,系統記憶體不夠用時會會繼續發送,如果還得不到處理就會強制退出程式。下面看具體的loadView和unloadView時候都會做什麼操作。

  1)Load週期


  當需要顯示或者訪問view屬性時,view沒有創建的話,VC就會調用loadView方法,在這個時候會創建一個view並將其賦給VC.view屬性。緊接著就會調用VC的viewDidLoad方法,這個時候VC.view保證是有值的,可以做進一步的初始化操作,例如添加一些subview。注意:定制VC時,如果覆蓋loadView方法,不需要調用[super loadView]方法。

  2)Unload週期



  當app收到記憶體警告的時候,會調用每一個VC的didRecieveMemoryWarning方法,我們需要做出回應,釋放程式中暫時不需要的資源。通常都會重寫該方法,重寫時候需要調用super的該方法。如果檢測到當前VC的view可以被安全釋放的話,就會調用viewWillUnload方法,這個我們必須要重視,因為當VC的view消失時候它的subviews可能會被一起釋放,我們需要根據具體情況做一些記錄,以保證下次能夠正確創建,同時不出現記憶體洩漏。調用viewWillUnload以後,會將VC.view屬性設置成nil,然後在調用viewDidUnload方法,這個時候我們可以釋放那些強引用的物件。

官方文檔:The View Controller Life Cycle

2012年8月7日 星期二

pushViewController 無效的問題


最近在新建的單元測試專案都是使用Single View Application專案型態。
但當要產生第二個頁面時,使用


    if(self.navigationController != nil)
        [self.navigationController pushViewController:controller animated:YES];

一直Push失效,原因是 self.navigationController 是 nil。

只要改一下AppDelegate.h 及 AppDelegate.m 即可。

FacebookDemoAppDelegate.h

























FacebookDemoAppDelegate.m





2012年7月24日 星期二

iPhone App 應用程式的生命週期


主題: iPhone App 應用程式的生命週期


心得:

l   今天拿到Android App開發基礎班的課程表,發現有一個section特別介紹Android App的生命週期,於是我也去網路搜尋IOS App相關的生命週期資訊,如下面二圖描述非常詳細。

l   我有使用一種月曆記事的app,通常我有設密碼,只要app被置於背景(非關閉App)後再被開啟,都會要求我重新輸入密碼,這樣的功能就可以寫在Application Delegate 派遺以下兩個方法applicationWillEnterForeground 以及 applicationDidBecomeActive,我可以在程式裡面去撰寫相對應的 Event


l   超重要的發現:
n   當應用程式在執行時突然有來電或是簡訊時,這個時後應用程式會受到干擾而中斷,這時後applicationWillResignActive: 會被呼叫。
n   如果使用者忽略這個中斷事件時,則會呼叫 applicationWillBecomeActive 這個方法來恢復程式的狀態。否則應用程式會進入背景狀態,進而呼叫applicationDidEnterBackground:
n   要特別注意的是,我應該在applicationWillResignActive: 妥善保存執行時的狀態,然後在applicationWillBecomeActive: 恢復應用程式的狀態。



2012年3月15日 星期四

移除 xcode

我升級成4.3版本後,不小心沒有勾選移除4.2的版本,然後就整個不開心。
可以開啟終端機,下列印的指令,清除乾淨Xcode:

# sudo /Developer/Library/uninstall-devtools --mode=all













2012年3月12日 星期一

[objective C] 判斷字串是否含有某些字串

NSString *string = @"hello bla bla";
if ([string rangeOfString:@"bla"].location == NSNotFound) {
  NSLog(@"string does not contain bla");
} else {
  NSLog(@"string contains bla!");
}
或是
if ([string rangeOfString:@"bla"].location != NSNotFound)
NSLog(@"string contains bla!");

[objective C] 指定UIDatePicker的初始時間

一般來說UIDatePicker起始為系統今天的日期,若要另外指定UIDatePicker的初始時間:


    NSDateFormatter *inputFormat = [[NSDateFormatter alloc] init];
    [inputFormat setDateFormat:@"yyyy/MM/dd"];
    NSDate *inputDate = [inputFormat dateFromString: @"2011/01/01"];  

    [datePicker setDate:inputDate];

2012年2月16日 星期四

[objective C] iPhone 轉 Universal

最近要練習將以前寫的iPhone 程式轉換為Universal 型態,Universal其實就是指可以同時在iPhone 和 iPad裝置上安裝使用,可以針對不同裝置的顯現樣板,在同一個專案裡同時被實現。如果你的APP要比較有遠景的話,這是必須的。

這時後就很慶幸開發方式是標準的MVC架構,我可以設定iPhone.xib與iPad.xib共用同一個class,這樣內部的程式就不需要全部改寫。

一、設定專案型態為Universal:
       專案的Targets/Summary/Devices ,改為Universal。

二、新增iPad.xib 且要共同原來的class:
        1.新增new file,選擇"UIViewController subclass",請注意要勾選 「Targeted for iPad」,取名可以是「原名-iPad」比較好分辨。
        2.刪除 *-iPad.h 和 *-iPad.m 。
        3.點選 *-iPad.xib,再選取它的 File's Owner,將Custom Class 由「原名-iPad」改為[原名],這個是很重要的步驟,因為 *-iPad.xib 就會和 *-iPhone.xib 共用同一個Class。

三、從 .m 檔用程式判斷目前的裝置,再決定要載入 *-iPad.xib 或 *-iPhone.xib 以顯示不同的畫面。

NewsViewController *plvc = nil;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone
        plvc = [[NewsViewController alloc] initWithNibName:@"NewsViewController" bundle:nil];
    else
        plvc = [[NewsViewController alloc] initWithNibName:@"NewsViewController-iPad" bundle:nil];


接下來也是練功的部份,我也要加油!

YES! 又多學到一手了~









    2012年2月9日 星期四

    [objective C] UIPickerView

    UIPickerView 物件的使用為例,這樣種有特定資料的互動,它可以把字串回傳給選擇器,然後顯示於畫面。許多控制項都有屬於自己的delegate及datasource。

    [Datasource]

    提供在控制項與它需要展示之資料間的橋樑。控制項會問datasource它需要什麼,datasource則負責以控制項期望的格式提供資訊。

    遵循 UIPickerViewDatasource協定。
    需在*.m實作的方法:

    - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component



    [Delegate]

    delegate負責元素的行為。


    遵循 UIPickerViewDelegate協定。
    需在*.m實作的方法:
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component




    [Protocol]
    在 .h 檔要註明需遵守的協定:

    @interface ViewController : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate>


    最後別忘了在 XIB 檔幫 UIPickerView 和 File's Owner 連結delegate及datasource。如果少了一個步驟都有可能出錯,可能執行後在編譯器沒有看到PickerView物件,或是一編譯就直接當掉。

    希望我可以記下來,下次應用在別的物件! Peggy加油~