iOS基礎--沙盒-數據本地化-歸解檔-整理總結(1)

惜春長怕花開早,何況落紅無數!<圓陸鯊>

<h1>沙盒機制:</h1>

沙盒 : 每個iOS應用程序都會為自己創建一個文件系統目錄(文件夾),這個<big>獨立,封閉,安全</big>的空間 ,叫做沙盒 ,是一種安全體系.

注意:

  • 1: 每一個應用程序都會擁有一個應用程序沙盒

  • 2: 應用程序沙盒就是一個系統目錄

  • 3: 所有的非代碼文件都保存在這個地方比如圖片, 聲音, 屬性列表(plist), sqlite數據庫和文本文件等.

  • 獨立: 不可能出現兩個程序公用同一個沙盒

  • 封閉 : 每一個沙盒 都只能他自己的應用去使用(很少的有和其他的app交互的,iOS8部分開放訪問也允許了用的并不多,應用程序向外請求或者接收數據都需要經過權限認證)

  • 安全 :沙盒有被刪除的時效


查找某個應用的沙盒

第一種方式: 上圖 點擊左上面的 <big>前往</big>--> <big>按住Alt鍵</big> --><big>選中資源庫</big> --> <big>選中Developer文件夾 </big> --> <big> CoreSimulator</big> --> <big>Devices</big> --> <big>模擬器路徑</big>

第一步:
第二步:

第二種方式: 上圖:


<h2>文件夾:</h2>

  • <u><h4>Documents</h4></u> :
    1: 存入一些永遠不被刪除的文件(不會被系統主動刪除),itunes備份時,同時也會備份Documents文件(條件: 盡量不在Documents放入音頻視頻等太大的東西,只放一些重要文件,以免審核被拒) 注 :可以存,有方法讓審核通過
  • <u><h4>Documents下的inbox文件</h4></u>: 該文件是用來保存其他應用程序請求,在當前應用程序打開的文件 例如: 應用 A 中有一個文件,可以被應用B打開.那么應用B就創建一個文件 C 去保存 A 中可被 B 打開的文件 (將A的文件復制到C 中),再讓 B 打開 A中的文件,而這個 C 就是inbox文件. (例如微信中打開網頁).
  • <u><h4>Library</h4></u>
    1. Caches : 存儲緩存的文件夾 當用戶對某一個URL做請求操作的時候,這個URL里面的東西會保存在主機里面的某個位置 . Cookie 和Session . (itunes不會備份此目錄,文件不會再應用退出時刪除,一般存放比較大,不是特別重要的資源)
  • 2: Preferences 保存應用的所有偏好設置.iOS的Settings (夜間模式, 無圖模式, 淘寶登錄信息, 永久存儲是否或者去獲取地理位置) 應用會該目錄中查找應用的設置信息,iTunes會備份它, 注意: 不應該直接創建偏好設置文件,而是應該使用NSUserDefaults 類來取得和設置應用程序的偏好 存儲的用戶數據都會保存在該目錄下的.plist文件中.,通常情況下由系統維護 ,我們很少去操作.
  • <u><h4>tmp</h4></u> : 保存應用運行時所需的臨時數據,使用完畢后會將相應的文件從該目錄刪除.應用沒有運行時或者手機重啟時 ,系統也有可能會清除該目錄下的文件,iTunes 不會同步該目錄
  • <u><h4>.app文件</h4></u> :該目錄包含了應用程序的本身的數據,包括資源文件和可執行文件,程序啟動后會根據需求動態加載(懶加載)代碼 或者 資源到內存中.而且整個目錄是只讀的. 不會被iTunes 同步

獲取文件夾方法:

  • 第一種: 通過該NSSeach搜索文件夾得地址,能獲取Documents 和Library 內部文件夾地址, 但是不能獲取tmp文件夾得地址,其他的都可以獲取到.

    // NSDocumentDirectory 表示獲取Documents文件夾得地址
    // NSUserDomainMask 表示用戶的主目錄
    // 第三個參數表示 展開"~" 的地址,設置為YES 為完整路徑
    // NSSearchPathForDirectoriesInDomains獲取的是一個數組(NSArray<NSString *> *),數組只有一個元素,所以可以直接獲取objectAtIndex: 0 ;

NSString *documentPathStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSLog(@"%@",documentPathStr);
  • 第二種: 首先獲取沙盒主路徑的地址,然后拼接上想要去的文件夾的地址.

// 首先獲取沙盒主路徑的地址

NSString  *homePathStr = NSHomeDirectory();    NSLog(@"homePathStr = %@",homePathStr);```
// 其次: 在沙盒主路徑后拼接Documents,拼接出來documents文件夾的路徑
   ```code
 NSString *documentsPathStr = [homePathStr stringByAppendingPathComponent:@"Library/Caches"];
 NSLog(@"documents = %@",documentsPathStr);```
 //獲取tmp文件夾得路徑
 ```code
 NSString *tmpPathStr = NSTemporaryDirectory();
 NSLog(@"tmpPathStr = %@",tmpPathStr);

// 4.獲取.app文件: 該目錄包含了應用程序的本身的數據,包括資源文件和可執行文件,程序啟動后會根據需求動態加載(懶加載)代碼 或者 資源到內存中.而且整個目錄是只讀的. 不會被iTunes 同步

NSString *appPath = [[NSBundle mainBundle] resourcePath];
NSLog(@"appPath**右擊打開包內容**%@",appPath);

簡單對象的寫入與讀寫

<u>數據本地化: 簡單說就是把數據的,存儲到應用程序的沙盒里面</u>

  • 寫入
    // 1 . 要知道存到哪里 ,所以需要一個文件夾的路徑
NSString  *documentsPathStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];    NSLog(@"%@",documentsPathStr);    ```
// 2 . 知道要存什么,  創建數據    
```code
NSString  *str = @"hello world";    ```
// 3 . 要知道數據放哪里 , 創建一個路徑,路徑的終點局勢存數據的文件 Component(成分)    
```code
NSString  *strPath = [documentsPathStr stringByAppendingPathComponent:@"str.txt"];   ```
 // 4 . 寫入操作    
```obj 
// 參數: atomically : YES 正當手機沒電關機 會保存文件   
 //              NO   否    
// encoding : 編碼方式    
[str writeToFile:strPath atomically:YES encoding:NSUTF8StringEncoding error:nil];```
   
-  讀取

    // 通過路徑讀取數據,使用stringWithContentsOfFile方法,在讀取的時候,
```obj
參數1: 表示讀取文件的路徑,
參數2: 表示編碼格式,
參數3: 表示錯誤信息.
NSString *newStr = [NSString stringWithContentsOfFile:strPath encoding:NSUTF8StringEncoding error:nil];```

-----------------------
![簡單對象的寫入讀取方法](http://upload-images.jianshu.io/upload_images/1523603-f812d1715e502db8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

------------------
NSData數據讀取存儲:
------------
題外話:
```obj 
UIImage *image1 = [UIImage imageNamed:<#(nonnull NSString *)#>]; 
UIImage *image2 = [UIImage alloc]initWithContentsOfFile:<#(nonnull NSString *)#>];````
- 根據imageName獲取圖片:會在緩存里存一份,下次在獲取同名圖片,直接從緩存里取.
 - 優點:快,只有第一次的時候慢,但是之后再獲取的話會很快.   
 - 缺點:會浪費內存,如果只用致辭的話這塊內存就浪費掉了.   
- 根據ContentsOfFile獲取到的圖片:每次都會根據路徑去取圖片,不會占用內存.如果圖片只使用一次,推薦使用ContentsOfFile    

#####寫入:
// 第一步: 獲取路徑

    NSString*documentPathStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)objectAtIndex:0];
// 第二步: 創建一個UIimag的數據并轉化成NSData類型的對象
```obj
     UIImage*image = [UIImage imageNamed:@"123"];
//將UIImage類型對象轉化成NSData類型的
//第一個參數 :轉哪個UIImage類型對象
//第二個參數:壓縮系數,越小壓縮越厲害
    NSData *data =UIImageJPEGRepresentation(image, 1); ```
// 第三步: 拼接出最終的存儲地方
```obj
    NSString *stringPath = [documentPathStr stringByAppendingPathComponent:@"stringPath.txt" ];```
   
 // 第四步: 寫入
```obj
[data  writeToFile:stringPath atomically:YES];```
    
####讀取數據:
```obj
// 創建一個NSData類型數據 從文件中找到
NSData *newData = [NSData dataWithContentsOfFile:stringPath];
// 再轉成UIImage
UIImage *newImage = [UIImage imageWithData:newData];

復雜對象的寫入與讀取:

復雜對象是指:

在Foundation框架內不存在的數據類,如自定義Person類等 無法在程序內通過writeToFile: 這個方法寫入文件內 只能通過將負載對象轉化為NSData,即歸檔

  • 復雜對象寫入文件的過程:
    復雜對象---> 歸檔 ---> NSData --->writeToFile

  • 文件中讀取復雜對象的過程:
    讀取文件 ---> NSData --->反歸檔 --->復雜對象

  • 首先:復雜對象所屬的類要遵守 <NSCoding>協議

  • 其次:實現協議中的兩個方法:

  • (void)encodeWithCoder:(NSCoder *)aCoder;序列化
  • (id)initWithCoder:(NSCoder *)aDecoder:反序列化

--------------------
歸解檔:
--------------------

舉例建一個Person 類 有以下屬性
// 如果一個對象向直接寫入本地,那么這個對象需要遵守NSCoding協議
```obj
@interface Person : NSObject<NSCoding>
@property(nonatomic,copy)NSString * name;
@property(nonatomic,copy)NSString *gender;
@property(nonatomic,assign)NSUInteger  age;```

實現協議方法:
```obj
//歸檔
//在歸檔和解檔的時候,要把所有的屬性都進行歸解檔
- (void)encodeWithCoder:(NSCoder*)aCoder
{

[aCoder  encodeObject:self.nameforKey:@"name"];
[aCoder  encodeObject:self.genderforKey:@"gender"];
[aCoder  encodeInteger:self.ageforKey:@"age"];
}


//解檔
- (instancetype)initWithCoder:(NSCoder*)aDecoder
{
if(self= [super  init]) {
self.name= [aDecoder  decodeObjectForKey:@"name"];
self.gender= [aDecoder  decodeObjectForKey:@"gender"];
self.age= [aDecoder  decodeIntegerForKey:@"age"];}
returnself;
}

上代碼:
// 如果一個對象向直接寫入本地,那么這個對象需要遵守NSCoding協議
// 建一個實例對象

Person *person = [[Person alloc]init]; 
person.name = @"James"; 
person.gender = @"M";
person.age = 38 ;
  • 歸檔
    //將復雜對象歸檔之后存入本地
    //第 1 步: 創建一個NSMutableData ,用于保存歸檔后的對象(初始化歸檔工具)

    NSMutableData *data = [NSMutableData data];
    

    //第 2 步: 創建個歸檔工具

     NSKeyedArchiver *keyedArchiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
    

    //第 3 步: 歸檔

     [keyedArchiver encodeObject:person forKey:@"person"];
    

    //第 4 步: 結束歸檔

    [keyedArchiver finishEncoding];
    

    //這時候存Data存儲好數據

     NSLog(@"data = %@",data);
    

    //獲取,拼接寫入沙盒路徑

        NSString *documentPathStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
        NSString *dataPath = [documentPathStr stringByAppendingPathComponent:@"person.plist"] ;
    

    // 寫入

     [data writeToFile:dataPath atomically:YES];         
    
  • 解檔并使用
    //第 1 步: 從本地獲取到Data

     NSData  *newData = [NSData dataWithContentsOfFile:dataPath];
     NSLog(@"%@",newData);    
    

//第 2 步: 通過獲取到的data 創建一個解檔工具

  NSKeyedUnarchiver *keyedUnarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:newData];   

//第 3 步:創建一個Person對象,接收解檔結果

   Person *newPerson = [keyedUnarchiver decodeObjectForKey:@"person"];   

//第 4 步:結束解檔

  [keyedUnarchiver finishDecoding];    
  NSLog(@"%@",newPerson);      
  • 歸解檔是一種編碼方式,不是數據本地化的方式
  • 負載對象寫入本地實際上使用的還是writeToFile 的簡單寫入本地的方法
  • 整存整取 writeToFile
  • 在一個路徑下存數據,最后一次存進去的東西會覆蓋之前的

PS:下一篇在詳細寫點歸解檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容