數(shù)據(jù)存儲(chǔ)緩存

目錄

1.plist(屬性列表)文件
2.Preference\NSUserDefaults(偏好設(shè)置)
3.NSKetedArchiver(歸檔 - 解歸檔)
4.SQLite 與 FMDB
5.CoreData
6.鑰匙串 Keychain
7.云服務(wù) iCloud
8.YYCache 緩存
9.bbx 司機(jī)端舉例

數(shù)據(jù)存儲(chǔ)緩存

數(shù)據(jù)存儲(chǔ)緩存基礎(chǔ)知識(shí)

數(shù)據(jù)存儲(chǔ)也叫數(shù)據(jù)緩存也叫數(shù)據(jù)持久化山林。所謂的持久化就是將數(shù)據(jù)保存到硬盤(pán)中焕阿,使得在應(yīng)用程序或機(jī)器重啟后可以繼續(xù)訪(fǎng)問(wèn)之前保存的數(shù)據(jù)狈癞。在 iOS 開(kāi)發(fā)中有很多數(shù)據(jù)持久化的方案枣申,比如 plist、偏好設(shè)置饮亏、歸檔 - 解歸檔耍贾、SQLite、FMDB路幸、CoreData荐开、
Keychain 等。

內(nèi)存緩存:也叫網(wǎng)絡(luò)緩存简肴;是 App 在運(yùn)行的時(shí)候用到的晃听,你把他想成單例的存放。即指當(dāng)前程序運(yùn)行空間砰识,內(nèi)存緩存速度快容量小能扒,它是供 cpu 直接讀取,比如我們打開(kāi)一個(gè)程序辫狼,他是運(yùn)行在內(nèi)存中的赫粥,關(guān)閉程序后內(nèi)存又會(huì)釋放。內(nèi)存緩存的數(shù)據(jù)只保留在A(yíng)PP啟動(dòng)時(shí)予借,比如保存一些從服務(wù)端獲取到的數(shù)據(jù),來(lái)緩解服務(wù)器的壓力频蛔,并且節(jié)約了用戶(hù)流量和時(shí)間灵迫,提高了用戶(hù)使用體驗(yàn)。iOS 內(nèi)存分為5個(gè)區(qū):棧區(qū)晦溪,堆區(qū)瀑粥,全局區(qū),常量區(qū)三圆,代碼區(qū)狞换。

硬盤(pán)緩存:也叫本地緩存,還叫磁盤(pán)緩存舟肉;就是存在沙盒修噪。磁盤(pán)存儲(chǔ)又可以分為文件系統(tǒng)存儲(chǔ)和數(shù)據(jù)庫(kù)系統(tǒng)存儲(chǔ)。

相關(guān)鏈接:https://juejin.cn/post/6844903593913352206

內(nèi)存緩存的大致流程
磁盤(pán)存儲(chǔ)

1.內(nèi)存分區(qū)

內(nèi)存分區(qū)

2.內(nèi)存緩存和磁盤(pán)緩存的區(qū)別

緩存分為內(nèi)存緩存和磁盤(pán)緩存兩種路媚。

1.內(nèi)存是指當(dāng)前程序的運(yùn)行空間黄琼,緩存速度快容量小,是臨時(shí)存儲(chǔ)文件用的整慎,供 CPU 直接讀取脏款,比如說(shuō)打開(kāi)一個(gè)程序围苫,他是在內(nèi)存中存儲(chǔ),關(guān)閉程序后內(nèi)存就又回到原來(lái)的空閑空間撤师。內(nèi)存緩存適合存儲(chǔ)一些 app 高頻次使用剂府,并且所占空間不大的文件,比如 NSURLConnection 默認(rèn)會(huì)緩存資源在內(nèi)存剃盾。

2.磁盤(pán)是程序的存儲(chǔ)空間腺占,緩存容量大、讀取速度慢、可持久化。與內(nèi)存不同的是磁盤(pán)是永久存儲(chǔ)東西的平夜,只要里面存放東西全闷,不管運(yùn)行不運(yùn)行 ,他都占用空間挨约,磁盤(pán)緩存是存在 Library/Caches。磁盤(pán)存儲(chǔ)可以存儲(chǔ)一些需要持久化的文件,信息等临扮,簡(jiǎn)單的講就是 app 被殺死以后,文件仍然在教翩。

.內(nèi)存緩存
磁盤(pán)緩存

3.沙盒詳解

沙盒機(jī)制:iOS 為不同數(shù)據(jù)管理對(duì)存儲(chǔ)路徑做了規(guī)范杆勇,即在 iOS 中每個(gè) APP 都擁有自己的沙盒,APP 只能訪(fǎng)問(wèn)對(duì)應(yīng)沙盒中存儲(chǔ)的數(shù)據(jù)饱亿,iOS 是不允許跨越沙盒去訪(fǎng)問(wèn)數(shù)據(jù)的蚜退,所有的數(shù)據(jù)都是保存在該沙盒的三個(gè)子目錄下:Document、Library(Library/Caches彪笼,Library/Preference)钻注、temp。

說(shuō)明:

1.Bundle 和沙盒(sandbox)之間的區(qū)別:Bundle 是應(yīng)用程序在手機(jī)中的安裝路徑配猫。沙盒(sandbox)是專(zhuān)門(mén)來(lái)存儲(chǔ)當(dāng)前APP自己的數(shù)據(jù)的路徑幅恋。

2.Application(應(yīng)用程序包):包含了所有的資源文件和和可執(zhí)行文件,上架前經(jīng)過(guò)數(shù)字簽名泵肄,上架后不可修改捆交。

3.沙盒根目錄獲取:NSString *home = NSHomeDirectory();

相關(guān)鏈接:http://www.reibang.com/p/34cda6a121db

應(yīng)用沙盒文件夾

4.緩存做什么腐巢?

我們使用場(chǎng)景比如:離線(xiàn)加載品追,預(yù)加載,本地通訊錄...等系忙,對(duì)非網(wǎng)絡(luò)數(shù)據(jù)诵盼,使用本地?cái)?shù)據(jù)管理的一種,具體使用場(chǎng)景有很多。

5.NSCache

NSCache 是蘋(píng)果提供的一套緩存機(jī)制风宁,用法和 NSMutableDictionary 類(lèi)似洁墙,在
AFNetworking,SDWebImage戒财,Kingfisher 中都有用到热监。它相當(dāng)于字典的安全版本,不會(huì)出現(xiàn)多線(xiàn)程的問(wèn)題饮寞,線(xiàn)程安全的孝扛。

說(shuō)明:

1.當(dāng)內(nèi)存不足時(shí) NSCache 會(huì)自動(dòng)釋放內(nèi)存,NSCache 設(shè)置緩存對(duì)象數(shù)量和占用的內(nèi)存大小幽崩,當(dāng)緩存超出了設(shè)置會(huì)自動(dòng)釋放內(nèi)存苦始。

2.NSCache 是 Key-Value 數(shù)據(jù)結(jié)構(gòu),其中 key 是強(qiáng)引用慌申,不實(shí)現(xiàn) NSCoping 協(xié)議陌选,作為 key 的對(duì)象不會(huì)被拷貝。

NSCache
NSCache
  • 舉例:
@interface NSCacheVC ()<NSCacheDelegate>
@property (nonatomic, strong) NSCache *myCache;
@end

@implementation NSCacheVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor purpleColor];
    
    self.myCache = [[NSCache alloc]init];
    self.myCache.delegate = self;
    
    for (int i = 0; i<10; i++) {
        [self.myCache setObject:[NSString stringWithFormat:@"%d", i] forKey:@(i) cost: 1];
    }
    
    for (int i = 0; i<10; i++) {
        NSLog(@"NSCache取出---%@", [self.myCache objectForKey:@(i)]);
    }
    
    /// 清除緩存
    [self.myCache removeAllObjects];
    /// 設(shè)置緩存限制
    self.myCache.totalCostLimit = 5;
    
    NSLog(@"設(shè)置緩存限制后=================");
    
    for (int i = 0; i<10; i++) {
        // 設(shè)置成本數(shù)為1
        [self.myCache setObject:[NSString stringWithFormat:@"%d", i] forKey:@(i) cost: 1];
    }
    
    for (int i = 0; i<10; i++) {
        NSLog(@"NSCache取出---%@", [self.myCache objectForKey:@(i)]);
    }
    
    /// 清除緩存
    [self.myCache removeAllObjects];
    NSLog(@"設(shè)置緩存限制后但未設(shè)置成本數(shù)cost=================");
    
    for (int i = 0; i<10; i++) {
        [self.myCache setObject:[NSString stringWithFormat:@"%d", i] forKey:@(i)];
    }
    
    for (int i = 0; i<10; i++) {
        NSLog(@"NSCache取出---%@", [self.myCache objectForKey:@(i)]);
    }
    
    /// 清除緩存
    [self.myCache removeAllObjects];
    
}

// 即將回收對(duì)象的時(shí)候進(jìn)行調(diào)用蹄溉,實(shí)現(xiàn)代理方法之前要遵守NSCacheDelegate協(xié)議咨油。
- (void)cache:(NSCache *)cache willEvictObject:(id)obj{
    NSLog(@"NSCache回收---%@", obj);
}

@end
舉例說(shuō)明

1.plist(屬性列表)文件

plist:是一種明文的輕量級(jí)存儲(chǔ)方式,最常用的格式是 XML 格式柒爵,比如新建一個(gè)項(xiàng)目時(shí)系統(tǒng)會(huì)提供一個(gè) info.plist 文件役电,這種方式的安全性很低,一般使用 plist 文件存儲(chǔ)的數(shù)據(jù)都是不需要加密棉胀,存儲(chǔ)少量法瑟,簡(jiǎn)單的不重要數(shù)據(jù),plist 文件能存儲(chǔ)字典和數(shù)組唁奢,不能存儲(chǔ)自定義對(duì)象瓢谢。

說(shuō)明:

屬性列表是一種 XML 格式的文件,拓展名為 plist 如果是對(duì) NSString驮瞧、NSDictionary、NSArray枯芬、NSData论笔、NSNumber 等類(lèi)型以及他們的可變類(lèi)型等,就可以使用 writeToFile:atomically: 方法直接將對(duì)象寫(xiě)到屬性列表文件中存儲(chǔ)千所,讀取時(shí)使用 arrayWithContentsOfFile:(數(shù)組)狂魔、dictionaryWithContentsOfFile(字典)等方法。

屬性列表 - NSDictionary 的存儲(chǔ)和讀取過(guò)程

使用場(chǎng)景:

主要是用于不用加密的數(shù)據(jù)存儲(chǔ)淫痰,比如在添加地址中使用的 pickerView 中的 cities.plist 文件最楷。

舉例:

/**
 *  Plist文件
 */

- (void)setUpPlist {

    NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [path stringByAppendingPathComponent:@"Person.plist"];

    NSDictionary *dict = @{
                           @"name" : @"William",
                           @"age" : @18,
                           @"height" : @1.75f
                           };

    // 將數(shù)據(jù)寫(xiě)入Plist
    [dict writeToFile:filePath atomically:YES];
    NSLog(@"%@", filePath);

    // 讀取plist中的數(shù)據(jù)
    NSDictionary *dicts = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"dict = %@",dicts);
    NSString *str = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"str = %@", str);
}
NSDictionary 用 plist 進(jìn)行儲(chǔ)存和讀取

plist 文件其他補(bǔ)充:

plist文件是將某些特定的類(lèi),通過(guò)XML文件的方式保存在目錄中,可以被序列化的類(lèi)型只有如下幾種:

NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;

1.獲得文件路徑:
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];

2.存儲(chǔ):
NSArray *array = @[@"123", @"456", @"789"];
[array writeToFile:fileName atomically:YES];

3.讀茸阉铩:
NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"%@", result);

4.注意:
只有以上列出的類(lèi)型才能使用plist文件存儲(chǔ)烈评,不能直接存儲(chǔ)自定義模型對(duì)象,如果要自定義則只能將自定義模型對(duì)象轉(zhuǎn)換為字典存儲(chǔ)犯建。
存儲(chǔ)時(shí)使用 writeToFile: atomically: 方法讲冠,其中 atomically 表示是否需要先寫(xiě)入一個(gè)輔助文件,再把輔助文件拷貝到目標(biāo)文件地址适瓦。這是更安全的寫(xiě)入文件方法竿开,一般都寫(xiě) YES。
讀取時(shí)使用 arrayWithContentsOfFile: 方法玻熙。
plist 只能識(shí)別字典否彩,數(shù)組。
如果想在plist文件中添加相關(guān)屬性嗦随,有兩個(gè)方法:1.直接添加列荔、2.在其源代碼中添加即可
如果想在plist文件中添加相關(guān)屬性,有兩個(gè)方法:1.直接添加称杨、2.在其源代碼中添加即可

2.Preference\NSUserDefaults(偏好設(shè)置)

很多 iOS 應(yīng)用都支持偏好設(shè)置來(lái)存儲(chǔ)數(shù)據(jù)肌毅,比如保存用戶(hù)名、密碼姑原、字體大小等設(shè)置悬而,iOS 提供了一套標(biāo)準(zhǔn)的解決方案來(lái)為應(yīng)用加入偏好設(shè)置功能,每個(gè)應(yīng)用都有個(gè) NSUserDefaults 實(shí)例锭汛,通過(guò)它來(lái)存取偏好設(shè)置笨奠。注意偏好設(shè)置也不能存儲(chǔ)自定義對(duì)象。

說(shuō)明:

1.偏好設(shè)置是專(zhuān)門(mén)用來(lái)保存應(yīng)用程序的配置信息的唤殴, 一般情況不要在偏好設(shè)置中保存其他數(shù)據(jù)般婆。如果利用系統(tǒng)的偏好設(shè)置來(lái)存儲(chǔ)數(shù)據(jù),默認(rèn)就是存儲(chǔ)在 Preferences 文件夾下面的朵逝,偏好設(shè)置會(huì)將所有的數(shù)據(jù)都保存到同一個(gè)文件中蔚袍。使用偏好設(shè)置對(duì)數(shù)據(jù)進(jìn)行保存之后,它保存到系統(tǒng)的時(shí)間是不確定的配名,會(huì)在將來(lái)某一時(shí)間點(diǎn)自動(dòng)將數(shù)據(jù)保存到 Preferences 文件夾下面啤咽。

2.如果需要即刻將數(shù)據(jù)存儲(chǔ),可以使用 [defaults synchronize]渠脉,因?yàn)?UserDefaults 設(shè)置數(shù)據(jù)時(shí)不是立即寫(xiě)入宇整,而是根據(jù)時(shí)間戳定時(shí)地把緩存中的數(shù)據(jù)寫(xiě)入本地磁盤(pán),所以調(diào)用了 set 方法之后數(shù)據(jù)有可能還沒(méi)有寫(xiě)入磁盤(pán)應(yīng)用程序就終止了芋膘。出現(xiàn)以上問(wèn)題鳞青,可以通過(guò)調(diào)用 synchornize 方法 [defaults synchornize]; 強(qiáng)制寫(xiě)入霸饲。

3.所有的信息都寫(xiě)在一個(gè)文件中,對(duì)比簡(jiǎn)單的 plist 可以保存和讀取基本的數(shù)據(jù)類(lèi)型臂拓,獲取 NSuserDefaults 保存(讀群衤觥)數(shù)據(jù)。

4.對(duì)于NSUerdefaults來(lái)說(shuō) 一般可以用來(lái)保存用戶(hù)的偏好設(shè)置 比如登陸賬號(hào) 密碼這些埃儿。 除此之外還可以用它來(lái)保存圖片器仗, 字符串 , 數(shù)字 和對(duì)象童番。它被保存到項(xiàng)目中的Plists文件里面里精钮。保存圖片 一般用它里面的兩個(gè)方法 圖片保存可以用PNG或者JPG對(duì)應(yīng)的方法 先轉(zhuǎn)換成NSData 再用NSUerdefaults保存 保存的時(shí)候?yàn)榱俗屗R上存下來(lái)要用synchronize 。它還可以用來(lái)在程序間進(jìn)行反向傳值剃斧。

5.注意:偏好設(shè)置是專(zhuān)門(mén)用來(lái)保存應(yīng)用程序的配置信息的轨香,一般不要在偏好設(shè)置中保存其他數(shù)據(jù);如果沒(méi)有調(diào)用synchronize方法幼东,系統(tǒng)會(huì)根據(jù)I/O情況不定時(shí)刻地保存到文件中臂容,所以如果需要立即寫(xiě)入文件的就必須調(diào)用synchronize方法;偏好設(shè)置會(huì)將所有數(shù)據(jù)保存到同一個(gè)文件中根蟹。即preference目錄下的一個(gè)以此應(yīng)用包名來(lái)命名的plist文件脓杉。

使用場(chǎng)景:

用來(lái)保存應(yīng)用程序設(shè)置和屬性、用戶(hù)保存的數(shù)據(jù)简逮。用戶(hù)再次打開(kāi)程序或開(kāi)機(jī)后這些數(shù)據(jù)仍然存在球散,比如保存用戶(hù)名、密碼散庶。

舉例:

舉例1
舉例2
舉例3
舉例4
舉例5

3.NSKetedArchiver(歸檔 - 解歸檔)

歸檔:即序列化蕉堰,將一個(gè) OC 對(duì)象轉(zhuǎn)換成 NSData(二進(jìn)制)的操作就叫做對(duì)象的序列化。解歸檔:即反序列化悲龟,將本地的二進(jìn)制數(shù)據(jù)轉(zhuǎn)為一個(gè) OC 對(duì)象的操作就叫做反序列化屋讶。OC 對(duì)象需要通過(guò)遵守 NSCoding 協(xié)議,并且實(shí)現(xiàn)協(xié)議中的兩個(gè)方法须教,才能支持序列化和反序列化操作皿渗。注意歸檔 NSCoding 可以存儲(chǔ)自定義對(duì)象。由于決大多數(shù)支持存儲(chǔ)數(shù)據(jù)的 Foundation 和 Cocoa Touch 類(lèi)都遵循了 NSCoding 協(xié)議轻腺,因此對(duì)于大多數(shù)類(lèi)來(lái)說(shuō)歸檔相對(duì)而言還是比較容易實(shí)現(xiàn)的羹奉。

說(shuō)明:

1.NSKeyedArchiver 如果對(duì)象是 NSString、NSDictionary约计、NSArray、NSData迁筛、NSNumber 等類(lèi)型煤蚌,可以直接用 NSKeyedArchiver 進(jìn)行歸檔和恢復(fù)耕挨。不是所有的對(duì)象都可以直接用這種方法進(jìn)行歸檔,只有遵守了 NSCoding 協(xié)議的對(duì)象才可以尉桩,并且實(shí)現(xiàn)協(xié)議中的兩個(gè)方法筒占。

2.NSCoding 協(xié)議有2個(gè)方法:
2.1 encodeWithCoder: 每次歸檔對(duì)象時(shí)都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何歸檔對(duì)象中的每個(gè)實(shí)例變量蜘犁,可以使用 encodeObject:forKey: 方法歸檔實(shí)例變量翰苫。
2.2 initWithCoder: 每次從文件中恢復(fù)(解碼)對(duì)象時(shí)都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何解碼文件中的數(shù)據(jù)為對(duì)象的實(shí)例變量这橙,可以使用 decodeObject:forKey 方法解碼實(shí)例變量奏窑。

3.如果需要?dú)w檔的類(lèi)是某個(gè)自定義類(lèi)的子類(lèi)時(shí),就需要在歸檔和解檔之前先實(shí)現(xiàn)父類(lèi)的歸檔和解檔方法屈扎。即 [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法埃唯,確保繼承的實(shí)例變量也能被編碼,即也能被歸檔鹰晨,以及也能被解碼墨叛,即也能被恢復(fù)。

4.將各種類(lèi)型的對(duì)象存儲(chǔ)到文件中模蜡,不僅僅是字符串或者字典漠趁,還能實(shí)現(xiàn)對(duì)自定義類(lèi)的對(duì)象進(jìn)行歸檔。

5.NSKeyedArchiver 是一種輕量級(jí)存儲(chǔ)的持久化方案忍疾,數(shù)據(jù)化歸檔時(shí)經(jīng)過(guò)加密處理的闯传,所以安全性遠(yuǎn)高于 plist,數(shù)據(jù)歸檔可以存儲(chǔ)一些復(fù)雜的對(duì)象膝昆,數(shù)據(jù)保存前會(huì)經(jīng)過(guò)二進(jìn)制處理丸边。

6.缺點(diǎn):它的局限是一次性讀取和存儲(chǔ)操作。歸檔的形式來(lái)保存數(shù)據(jù)只能一次性歸檔保存以及一次性解壓荚孵。所以只能針對(duì)小量數(shù)據(jù)妹窖,如果想改動(dòng)數(shù)據(jù)的某一小部分,需要解壓整個(gè)數(shù)據(jù)或者歸檔整個(gè)數(shù)據(jù)收叶。

歸檔 - 解歸檔骄呼,注意:必須遵循并實(shí)現(xiàn) NSCoding 協(xié)議、保存文件的擴(kuò)展名可以任意指定判没、繼承時(shí)必須先調(diào)用父類(lèi)的歸檔解檔方法

使用場(chǎng)景:

當(dāng)我們想要存儲(chǔ)一些更加復(fù)雜的自定義數(shù)據(jù)時(shí)蜓萄,如果我們的程序此時(shí)不需要執(zhí)行查詢(xún)數(shù)據(jù)、數(shù)據(jù)遷移等操作澄峰,或者是并非所有的數(shù)據(jù)都有發(fā)雜的關(guān)系圖嫉沽,這時(shí)候數(shù)據(jù)的歸檔方案是最適合的。使用 archive 格式的文件將歸檔的數(shù)據(jù)存儲(chǔ)在沙盒目錄下俏竞,這種格式讀取出來(lái)的是二進(jìn)制绸硕,需要用 NSKeyedUnarchiver 類(lèi)對(duì)該數(shù)據(jù)進(jìn)行解檔堂竟。

舉例:

舉例1:NSArray、Person 等歸檔
舉例2:NSData - 歸檔
舉例2:NSData - 解歸檔

舉例3:

Student.h

#import 
#import "Book.h"

@interface Student : NSObject 
@property(nonatomic, copy) NSString *name;//姓名
@property(nonatomic, assign) int age;//年齡
@property(nonatomic, strong) Book *book;//課本
@end

Student.m
#import "Student.h"

static NSString * const kStudentNameKey = @"kStudentNameKey";
static NSString * const kStudentAgeKey = @"kStudentAgeKey";
static NSString * const kBookKey = @"kBookKey";

@implementation Student

/**解檔(反序列化)*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self == [super init]) {
        self.name = [aDecoder decodeObjectForKey:kStudentNameKey];
        self.age = [aDecoder decodeIntForKey:kStudentAgeKey];
        self.book = [aDecoder decodeObjectForKey:kBookKey];
    }
    return self;
}

/**歸檔(序列化)*/
- (void)encodeWithCoder:(NSCoder *)aCoder {
    // 歸檔姓名(字符串對(duì)象)
    [aCoder encodeObject:self.name forKey:kStudentNameKey];
    // 歸檔年齡(注意:這是基本數(shù)據(jù)類(lèi)型, 如果是其他的類(lèi)型,直接調(diào)用對(duì)應(yīng)類(lèi)型的encode即可)
    [aCoder encodeInteger:self.age forKey:kStudentAgeKey];
    // 歸檔自定義類(lèi)(Book)對(duì)象
    [aCoder encodeObject:self.book forKey:kBookKey];
}
@end

/***************************************/
viewController.m
// 保存
- (IBAction)saveDatas:(id)sender {
    // 創(chuàng)建對(duì)象
    Student *student = [[Student alloc] init];
    student.name = @"Alex";
    student.age = 15;
    student.book.bookName = @"習(xí)近平中國(guó)特色社會(huì)主義";    // 獲取文件路徑
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [path stringByAppendingPathComponent:@"student.archiver"];    // 將自定義的對(duì)象保存到文件中,調(diào)用的是NSKeyedArchiver的類(lèi)方法
    BOOL flag = [NSKeyedArchiver archiveRootObject:student toFile:filePath];
    if (flag) {
        NSLog(@"如果來(lái)到這里說(shuō)明歸檔成功");
    }
 }

// 讀取
- (IBAction)readDatas:(id)sender {
    // 獲取文件保存的路徑
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [path stringByAppendingPathComponent:@"student.archiver"];
    // 打印文件保存的路徑
    NSLog(@"%@", filePath);
    // 從文件中讀取對(duì)象, 解檔對(duì)象就調(diào)用NSKeyedUnarchiver的一個(gè)類(lèi)方法,unarchiveObjectWithFile: 即可
    Student *student = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    if (student) {
        // 來(lái)到這里說(shuō)明讀取成功
        NSLog(@"%@, %d, %@", student.name, student.age, student.book.bookName);
    }
}

舉例4:

舉例5:

舉例6 - NSKeyedArchiver 簡(jiǎn)單使用說(shuō)明:

NSCoding協(xié)議聲明了兩個(gè)方法玻佩,這兩個(gè)方法都是必須實(shí)現(xiàn)的出嘹。一個(gè)用來(lái)說(shuō)明如何將對(duì)象編碼到歸檔中,另一個(gè)說(shuō)明如何進(jìn)行解檔來(lái)獲取一個(gè)新對(duì)象咬崔。

1.遵循NSCoding協(xié)議 
@interface Person : NSObject <NSCoding>

2.設(shè)置屬性
@property (strong, nonatomic) UIImage *avatar;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
@end

3.實(shí)現(xiàn)協(xié)議方法 
 解檔:
- (id)initWithCoder:(NSCoder *)aDecoder {
   if ([super init]) {
       self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
       self.name = [aDecoder decodeObjectForKey:@"name"];
       self.age = [aDecoder decodeIntegerForKey:@"age"];
   }
   return self;
}

歸檔:
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.avatar forKey:@"avatar"];
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInteger:self.age forKey:@"age"];
  }

特別注意:如果需要?dú)w檔的類(lèi)是某個(gè)自定義類(lèi)的子類(lèi)時(shí)税稼,就需要在歸檔和解檔之前先實(shí)現(xiàn)父類(lèi)的歸檔和解檔方法。即 [super encodeWithCoder:aCoder] 
和 [super initWithCoder:aDecoder] 方法; 

其他使用說(shuō)明:

需要把對(duì)象歸檔是調(diào)用NSKeyedArchiver的工廠(chǎng)方法 archiveRootObject: toFile: 方法:
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
Person *person = [[Person alloc] init];
person.avatar = self.avatarView.image;
person.name = self.nameField.text;
person.age = [self.ageField.text integerValue];
[NSKeyedArchiver archiveRootObject:person toFile:file];

需要從文件中解檔對(duì)象就調(diào)用NSKeyedUnarchiver的一個(gè)工廠(chǎng)方法 unarchiveObjectWithFile: 即可:
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
if (person) {
   self.avatarView.image = person.avatar;
   self.nameField.text = person.name;
   self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
  }

4.SQLite 與 FMDB

https://juejin.cn/post/7156037635943694349

  • SQLite

SQLite 是嵌入式關(guān)系型數(shù)據(jù)庫(kù)垮斯,是一個(gè)輕量級(jí)跨平臺(tái)的小型數(shù)據(jù)庫(kù)郎仆,是一種基于C語(yǔ)言開(kāi)發(fā)的輕型數(shù)據(jù)庫(kù),其最主要的特點(diǎn)就是輕量級(jí)甚脉、跨平臺(tái)丸升,當(dāng)前很多嵌入式操作系統(tǒng)都將其作為數(shù)據(jù)庫(kù)首選。雖然 SQLite 是一款輕型數(shù)據(jù)庫(kù)牺氨,但是其功能也絕不亞于很多大型關(guān)系數(shù)據(jù)庫(kù)狡耻。SQLite3:操作數(shù)據(jù)比較快、可以局部讀取猴凹、比較小型夷狰,占用的內(nèi)存資源比較少。splite 可移植性比較高郊霎,有著和 MySpl 幾乎相同的數(shù)據(jù)庫(kù)語(yǔ)句沼头,它的處理速度比 Mysql、PostgreSQL 這兩款著名的數(shù)據(jù)庫(kù)都還快书劝,以及無(wú)需服務(wù)器即可使用的優(yōu)點(diǎn)进倍。

1.在 iOS 中需要用 C 語(yǔ)言進(jìn)行對(duì)數(shù)據(jù)庫(kù)的操作、訪(fǎng)問(wèn)(無(wú)法用 oc购对,因?yàn)?libsqlite3 框架基于 C 語(yǔ)言編寫(xiě))猾昆。
2.SQLite 采用動(dòng)態(tài)數(shù)據(jù)類(lèi)型。
3.要使用 SQLite 很簡(jiǎn)單骡苞,如果在 Mac OSX 上使用可以考慮到 SQLite 官方網(wǎng)站下載命令行工具垂蜗,也可以使用類(lèi)似于 SQLiteManager、Navicat for SQLite 等工具解幽。

相關(guān)鏈接:https://juejin.cn/post/6844903793327341575

SQLite 常用命令:

啟動(dòng) SQLite:在終端鍵入 sqlite3贴见,提示符變成 sqlite>

.help --- 顯示幫助信息
.quit/.exit --- 退出
.open --- 打開(kāi)指定的數(shù)據(jù)庫(kù)文件
.save --- 將內(nèi)存中的數(shù)據(jù)庫(kù)保存到指定的文件
.databases --- 顯示數(shù)據(jù)庫(kù)的信息
.schema ?TABLE? --- 顯示表結(jié)構(gòu)
.tables ?PATTERN? --- 顯示所有的表
.mode MODE --- 設(shè)置輸出模式
.stats ON|OFF --- 開(kāi)啟或關(guān)閉統(tǒng)計(jì)信息
.dump ?TABLE?--- 以SQL文本格式轉(zhuǎn)存數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)(SQLite)優(yōu)缺點(diǎn):

優(yōu)點(diǎn)

1.該方案可以存儲(chǔ)大量的數(shù)據(jù),存儲(chǔ)和檢索的速度非扯阒辏快片部。
2.能對(duì)數(shù)據(jù)進(jìn)行大量的聚合,這樣比起使用對(duì)象來(lái)講操作要快霜定。

缺點(diǎn)

1.它沒(méi)有提供數(shù)據(jù)庫(kù)的創(chuàng)建方式
2.它的底層是基于C語(yǔ)言框架設(shè)計(jì)的档悠,沒(méi)有面向?qū)ο蟮?API捆探,用起來(lái)非常麻煩。
3.發(fā)雜的數(shù)據(jù)模型的數(shù)據(jù)建表站粟,非常麻煩。

在實(shí)際開(kāi)發(fā)中我們都是使用的是 FMDB 第三方開(kāi)源的數(shù)據(jù)庫(kù)曾雕,該數(shù)據(jù)庫(kù)是基于 splite 封裝的面向?qū)ο蟮目蚣堋?/strong>

SQLite3

舉例 - 以學(xué)生表為例講解相關(guān)基本知識(shí):

schema  TbStudent查看學(xué)生表內(nèi)容
tables列出所有表
header on 顯示表頭

—插入數(shù)據(jù):
insert into TbStudent values(1001,'王大錘','男','重慶萬(wàn)州','1990-1-6');
insert into TbStudent (stuid,stuname) values(1002,'李林’);//部分項(xiàng)

—查詢(xún)所有行所有列
select * from TbStudent;

—?jiǎng)h除數(shù)據(jù)(要加條件奴烙,否則刪除全部;下面同這)
delete from TbStudent where stuid=1004;

—更新數(shù)據(jù)
update TbStudent set stuaddr='四川綿陽(yáng)',stubirth='1993.12.3' where stuid=1002;
(其中1002的沒(méi)有加地址和出生)

--投影操作
select stuname,stusex from TbStudent;
--投影時(shí)別名(as可省剖张,別名用法)
select stuname as 姓名 , stusex as 性別 from Tbstudent;

--數(shù)據(jù)篩選(可加關(guān)系:and or)
select *from TbStudent where stusex='女';
select *from TbStudent where stusex='女' and stuaddr='南京';
select *from TbStudent where stusex='女' or stubirth='1998-1-6';
select *from TbStudent where stubirth between '1985-1-1' and '1990-12-12';
select *from TbStudent where stubirth<'1990-12-1';

--模糊查詢(xún)
select *from TbStudent where stuname like '王%';匹配任意多個(gè)字符
select *from TbStudent where stuname like'%王%';只要名字中有王字
select *from TbStudent where stuname like'王_';匹配精確一個(gè)字符
select *from TbStudent where stuname like'王__';

--排序(默認(rèn)是升序的asc(可是芯鳌);降序desc)[同時(shí)用篩選和排序搔弄,先篩后排]
select *from TbStudent order by stubirth;
select *from TbStudent order by stubirth desc;
select *from TbStudent order by  stusex, stubirth desc;//先排性別后排出生

--統(tǒng)計(jì)數(shù)
select count(stusex) 總?cè)藬?shù) from TbStudent;

--分組
select stusex,count(stusex)from TbStudent  group by stusex;//男女各多少人
select stuaddr 家庭住址,count(stuaddr)as 總?cè)藬?shù) from TbStudent group by stuaddr order by  總?cè)藬?shù);

--聚合函數(shù)幅虑、分組函數(shù)
count 
max 
min
avg:平均數(shù)
sum

-----子查詢(xún)(把一個(gè)查詢(xún)的結(jié)果作為另一個(gè)查詢(xún)的一部分來(lái)使用)
select  stuname, stubirth  from TbStudent where stubirth=(select min (stubirth) from TbStudent);//年齡最大的名字

select min(stubirth) from TbStudent;//選擇出年齡最大

—分頁(yè)查詢(xún)(limit a,b—>a是第幾條,b是從這條開(kāi)始依次查b個(gè))
select  * from  tbemp order by sal desc limit 10,5;//第10到14

-------連接查詢(xún)(一次查詢(xún)多張表)-----
  --->內(nèi)連接
  --->外連接 ---> 左外連接(SQLite只支持左;即不管是否滿(mǎn)足連接顾犹,都寫(xiě)出來(lái)倒庵,不滿(mǎn)足的地方補(bǔ)空)、右外連接炫刷、全外連接
//以TbDept表和TbEmp表為例:
(注意:連接兩張表時(shí)如果沒(méi)有連接條件將產(chǎn)生笛卡爾積)
 寫(xiě)法1:=
select empno,name,job,dname,dloc  from TbEmp, Tbdept where TbEmp.dno =TbDept.deptno;
***
select empno,name,job,dname,dloc  from TbEmp as t1,  Tbdept as t2  where t1.dno =t2.deptno;

寫(xiě)法2:… inner jion  … on 

select empno, name, job, dname, dloc  from TbEmp, inner join 
TbDept  on  dno = deptno;
***
select empno, name, job, dname, dloc  from TbEmp as t1 inner join  TbDept as t2 on t1.dno = t2.deptno;

***查詢(xún)薪水超過(guò)其所在部門(mén)平均薪水的員工的姓名擎宝、部門(mén)編號(hào)和工資
SELECT  ename,deptno,sal from TbEmp as t1 inner join TbDept as t2 on sal>(SELECT avg(sal)from TbEmp where t1.dno=t2.deptno );
***查詢(xún)部門(mén)中薪水最高的人姓名、工資和所在部門(mén)名稱(chēng)
SELECT ename,sal,dname from TbEmp as t1 inner join TbDept as t2 on sal=(SELECT max(sal) from TbEmp where t1.dno=t2.deptno);
***注意學(xué)會(huì)創(chuàng)建臨時(shí)表    
寫(xiě)在前面的是左表浑玛;寫(xiě)在后面的右表
  • FMDB

FMDB 是 iOS 平臺(tái)的 SQLite 數(shù)據(jù)庫(kù)框架绍申,F(xiàn)MDB 以 OC 的方式封裝了 SQLite 的 C 語(yǔ)言 API 即基于 SQLite3 封裝的一套 OC 的 API 庫(kù)。因?yàn)?SQLite 的操作都是比較底層的 C 函數(shù)用起來(lái)比較麻煩顾彰,F(xiàn)MDB 對(duì)這些底層的東西進(jìn)行了面向?qū)ο蟮姆庋b极阅,是一個(gè)非常好用的第三方庫(kù),使用時(shí)需要添加蘋(píng)果提供的依賴(lài)庫(kù) libsqlite3.dylib涨享。FMDB的gitHub地址

其優(yōu)點(diǎn):
1.使用起來(lái)更加面向?qū)ο蠼畈∪チ撕芏嗦闊⑷哂嗟腃語(yǔ)言代碼灰伟。
2.對(duì)比蘋(píng)果自帶的 CoreData 框架拆又,更加輕量級(jí)和靈活。
3.提供了多線(xiàn)程安全的數(shù)據(jù)庫(kù)操作方法栏账,有效地防止數(shù)據(jù)混亂帖族。

相關(guān)鏈接:
https://juejin.cn/post/6844903805369188359
https://juejin.cn/post/7075274270472945671

FMDB 的核心 API:

FMDatabase:代表數(shù)據(jù)庫(kù)
FMResultSet:代表操作查詢(xún)結(jié)果的游標(biāo)
FMDatabaseAdditions:對(duì) FMDatabase 類(lèi)擴(kuò)展的 Category
FMDatabasePool:數(shù)據(jù)庫(kù)連接池支持類(lèi)
FMDatabaseQueue:數(shù)據(jù)庫(kù)多線(xiàn)程操作支持類(lèi)

FMDB 舉例講解:

2.例子講解
// 創(chuàng)建數(shù)據(jù)庫(kù)
- (void) createDb {
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/test.db"];
    NSLog(@"%@", path);
    self.db = [[FMDatabase alloc] initWithPath:path];
    if([self.db open]) {
        [self createTable];
    }
    else {
        NSLog(@"創(chuàng)建數(shù)據(jù)庫(kù)失敗!");
    }
}

// 創(chuàng)建表
- (void) createTable {
    NSString *sql = @"create table if not exists tb_user (username varchar(20) primary key, password varchar(20) not null, email varchar(50));";
    if([self.db executeUpdate:sql]) {
        [self insertData];
    }
    else {
        NSLog(@"創(chuàng)建用戶(hù)表失敗!");
    }
}

// 插入數(shù)據(jù)
- (void) insertData {
    NSString *sql = @"insert into tb_user values (?,?,?);";
    if([self.db executeUpdate:sql, @"jackfrued", @"123456", @"jackfrued@126.com"]) {
        
    }
    else {
        NSLog(@"插入數(shù)據(jù)失敗!");
    }
}

// 顯示表中的記錄
- (void) showRecords {
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/test.db"];
    self.db = [[FMDatabase alloc] initWithPath:path];
    if([self.db open]) {
        NSString *sql = @"select * from tb_user";
        FMResultSet *rs = [self.db executeQuery:sql];
        NSLog(@"%d", rs.next);
        while([rs next]) {
            NSLog(@"Username: %@", [rs stringForColumn:@"username"]);
            NSLog(@"Password: %@", [rs stringForColumn:@"password"]);
            NSLog(@"Email: %@", [rs stringForColumn:@"email"]);
        }
        
        [self clearData];
    }
    else {
        NSLog(@"創(chuàng)建數(shù)據(jù)庫(kù)失敗!");
    }
}

- (void) clearData {
    NSString *sql = @"delete from tb_user";
    if([self.db executeUpdate:sql]) {
        NSLog(@"清理數(shù)據(jù)成功!!!");
    }
}
  • 數(shù)據(jù)庫(kù)補(bǔ)充說(shuō)明

數(shù)據(jù)庫(kù)概念 (.db):
數(shù)據(jù)的集散地,有效地存儲(chǔ)和管理數(shù)據(jù)挡爵。App如果有大量的數(shù)據(jù)需要進(jìn)行本地存儲(chǔ)就可以考慮使用數(shù)據(jù)庫(kù)技術(shù)竖般,它不僅能夠有效的存儲(chǔ)和管理數(shù)據(jù),更重要的是提供了方便的檢索數(shù)據(jù)的手段茶鹃。簡(jiǎn)單的說(shuō)涣雕,數(shù)據(jù)庫(kù)是實(shí)現(xiàn)數(shù)據(jù)持久化的重要方案艰亮,其他的方案包括:plist文件、archieve歸檔挣郭、NSUserDefaults迄埃、普通文件等。

數(shù)據(jù)庫(kù)類(lèi)型:
Oracle:甲骨文數(shù)據(jù)庫(kù)兑障,當(dāng)今牛逼關(guān)系型數(shù)據(jù)庫(kù)
DB2:IBM公司的產(chǎn)品侄非,數(shù)據(jù)倉(cāng)庫(kù)和數(shù)據(jù)挖掘功能非常強(qiáng)大
SQLServer:微軟的產(chǎn)品,適合微軟自己的Windows服務(wù)器環(huán)境
MySQL:開(kāi)源的數(shù)據(jù)庫(kù)產(chǎn)品流译,中小型站點(diǎn)的數(shù)據(jù)庫(kù)服務(wù)器首選

關(guān)系型數(shù)據(jù)庫(kù):比如 SQLite逞怨。
數(shù)據(jù)庫(kù)數(shù)據(jù):若只讀取不對(duì)其操作則保存在 Nsbundle,若對(duì)它要維護(hù)修改則放在沙箱中(數(shù)據(jù)要長(zhǎng)久放在 doucument)福澡,創(chuàng)建數(shù)據(jù)庫(kù)放沙箱的 doucument文件叠赦。

關(guān)系型數(shù)據(jù)庫(kù)特點(diǎn):

1.用二維表組織數(shù)據(jù)(行:一條記錄;列:一條字段)革砸,主鍵為能夠唯一標(biāo)識(shí)一條記錄的字段(比如庫(kù)中已有的學(xué)號(hào)除秀,再錄相同的不能錄),添加這個(gè) primary key 表示它是主鍵业岁。外鍵為其他表的主鍵(外來(lái)的主鍵)鳞仙,例如兩張表人與身份證例子,pragma foreign_key = on笔时。

2.結(jié)構(gòu)化查詢(xún)語(yǔ)言(SQL)- SQL分4部分:
DDL:數(shù)據(jù)定義語(yǔ)言create(創(chuàng)建棍好;可以加前綴命名—>如創(chuàng)建學(xué)生表: create Table TBstudent)/drop(刪除)/alter(修改)
DML:操作insert(添加)/delete(刪除)/update(更新)
DQL:查詢(xún)select (重點(diǎn))
DCL:控制grant/revoke

1.關(guān)系代數(shù)
2.集合論
3.實(shí)體關(guān)系圖(ER圖),實(shí)體間關(guān)系:一對(duì)一:人與身份證允耿、一對(duì)多:部門(mén)和員工借笙、多對(duì)一:讀者與圖書(shū)
4.事務(wù) ACID,即:Atomic较锡、Consistency业稼、Isolation、Duration蚂蕴;要么全成功低散,要么全失敗骡楼;要么全做熔号,要么全不做,以銀行轉(zhuǎn)賬為例鸟整。

5.CoreData

coreData 是蘋(píng)果官方在 iOS5 之后推出的綜合性數(shù)據(jù)庫(kù)引镊,其使用了對(duì)象關(guān)系映射技術(shù),將對(duì)象轉(zhuǎn)換成數(shù)據(jù),將數(shù)據(jù)存儲(chǔ)在本地的數(shù)據(jù)庫(kù)中弟头。coreData 為了提高效率需要將數(shù)據(jù)存儲(chǔ)在不同的數(shù)據(jù)庫(kù)中吩抓,比如在使用的時(shí)候,最好是將本地的數(shù)據(jù)保存到內(nèi)存中赴恨,這樣的目的是訪(fǎng)問(wèn)速度比較快疹娶。CoreData 本身并不是一個(gè)并發(fā)安全的架構(gòu),所以在多線(xiàn)程中實(shí)現(xiàn) CoreData 會(huì)有問(wèn)題伦连。

Core Data (ORM:可以將關(guān)系模型和對(duì)象模型互轉(zhuǎn))蚓胸,這個(gè)蘋(píng)果原生處理數(shù)據(jù)庫(kù)的非常難用,可選用第三方庫(kù) ObjectRecord 和 MagicalRecord除师。各類(lèi)應(yīng)用開(kāi)發(fā)中只要牽扯到數(shù)據(jù)庫(kù)操作通常都會(huì)用到一個(gè)概念“對(duì)象關(guān)系映射(ORM)iOS 中 ORM 框架首選 Core Data,這是官方推薦的不需要借助第三方框架扔枫。無(wú)論是哪種平臺(tái)汛聚、哪種技術(shù),ORM 框架的作用都是相同的短荐,那就是將關(guān)系數(shù)據(jù)庫(kù)中的表(準(zhǔn)確的說(shuō)是實(shí)體)轉(zhuǎn)換為程序中的對(duì)象倚舀,其本質(zhì)還是對(duì)數(shù)據(jù)庫(kù)的操作(例如 Core Data 中如果存儲(chǔ)類(lèi)型配置為 SQLite 則本質(zhì)還是操作的 SQLite 數(shù)據(jù)庫(kù))。使用 Core Data 進(jìn)行數(shù)據(jù)庫(kù)存取并不需要手動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)忍宋,這個(gè)過(guò)程完全由 Core Data 框架完成痕貌,開(kāi)發(fā)人員面對(duì)的是模型,主要的工作就是把模型創(chuàng)建起來(lái)糠排,具體數(shù)據(jù)庫(kù)如何創(chuàng)建則不用管。

相關(guān)鏈接:
https://juejin.cn/post/7011708888718245925
http://t.zoukankan.com/HJiang-p-7818418.html

CoreData

6.鑰匙串 Keychain

keychain 存儲(chǔ)在硬盤(pán)上,刪除了應(yīng)用干像,保存的數(shù)據(jù)還在图贸。每個(gè) APP 的 keychain 相對(duì)來(lái)說(shuō)是獨(dú)立的,但是也可以實(shí)現(xiàn) APP 之間 keychain 數(shù)據(jù)的共享乾闰,前提是同一個(gè) TeamID 下落追、且設(shè)置了數(shù)據(jù)共享。

Keychain 是 OS X 和 iOS 都提供一種安全地存儲(chǔ)敏感信息的工具涯肩,比如轿钠,存儲(chǔ)用戶(hù)ID,密碼病苗,私鑰和證書(shū)等疗垛。存儲(chǔ)這些信息可以免除用戶(hù)重復(fù)輸入用戶(hù)名和密碼的過(guò)程。Keychain Services 的安全機(jī)制保證了存儲(chǔ)這些敏感信息不會(huì)被竊取铅乡。簡(jiǎn)單說(shuō)來(lái)继谚,Keychain 就是一個(gè)安全容器。參考 apple 官網(wǎng)介紹

相關(guān)鏈接:
https://juejin.cn/post/6844903921765318669
https://juejin.cn/post/6952697138656575496
https://juejin.cn/post/6903710640817307655

Keychain 結(jié)構(gòu)說(shuō)明
Keychain
Keychain
Keychain
實(shí)現(xiàn)數(shù)據(jù)的共享
舉例 - 賬戶(hù)密碼自動(dòng)填充
舉例 - 賬戶(hù)密碼自動(dòng)填充

7.云服務(wù) iCloud

iCloud 文檔存儲(chǔ)功能來(lái)滿(mǎn)足應(yīng)用數(shù)據(jù)云存儲(chǔ)的需求,用戶(hù)可以在自己 iCloud 賬號(hào)下的任何設(shè)備訪(fǎng)問(wèn)或修改 App 的這部分?jǐn)?shù)據(jù)花履。iOS iCloud 存儲(chǔ)中芽世,蘋(píng)果提供了三個(gè)功能:Key-value storage、iCloud Documents诡壁、CloudKit济瓢。iCloud 存儲(chǔ)空間就是蘋(píng)果設(shè)備 icloud 云端數(shù)據(jù)存儲(chǔ)的空間,屬于一種云存儲(chǔ)妹卿,一般會(huì)自帶 5GB 的存儲(chǔ)空間旺矾,若用戶(hù)需要更大的存儲(chǔ)空間,是可以選擇購(gòu)買(mǎi)的夺克。

說(shuō)明:

  1. iCloud 可以在iOS 設(shè)備和 iPadOS 設(shè)備開(kāi)啟箕宙、鎖定并連接到電源時(shí),通過(guò) Wi-Fi 自動(dòng)備份您的設(shè)備铺纽,用戶(hù)可以使用 iCloud 云備份來(lái)恢復(fù) iOS 或 iPadOS 設(shè)備柬帕,或者無(wú)縫設(shè)置新設(shè)備。

2.查看在 iOS 設(shè)備狡门、iPadOS 設(shè)備和 Mac 上打開(kāi)的網(wǎng)站(iCloud 標(biāo)簽頁(yè))陷寝。即使在離線(xiàn)狀態(tài)下,也可以閱讀閱讀列表中的文章其馏。另外也可以在 iOS 設(shè)備凤跑、iPadOS 設(shè)備、Mac 和 Windows 電腦上使用相同的書(shū)簽叛复。請(qǐng)參閱 Safari 瀏覽器中的 iCloud 標(biāo)簽頁(yè)仔引、書(shū)簽和閱讀列表。

相關(guān)鏈接:
https://juejin.cn/post/6844903615723733000
https://baijiahao.baidu.com/s?id=1719371222823021907&wfr=spider&for=pc

iCloud

8.YYCache 緩存

相關(guān)鏈接:
https://juejin.cn/post/6844903776113917966
https://juejin.cn/post/6885605205380562952
https://juejin.cn/post/6844903694341767182

YYCache 整體框架設(shè)計(jì)圖

9.bbx 司機(jī)端舉例

舉例1:新訂單有個(gè)提示語(yǔ)新字

場(chǎng)景1:在任務(wù)列表接到新訂單或者在 App 中收到新訂單推送的時(shí)候褐奥,在任務(wù)列表頁(yè)面訂單 cell 上面會(huì)提示有個(gè)新字肤寝,地圖頁(yè)面氣泡有個(gè)新字,點(diǎn)擊操作改訂單(滑動(dòng)或者打電話(huà)抖僵、導(dǎo)航..)則表示已經(jīng)操作過(guò)不是新訂單了則去掉新字鲤看。這個(gè)通過(guò)判斷訂單 id 來(lái)區(qū)別,可以在訂單列表綁定的數(shù)據(jù)模型里面封裝:通過(guò) id 添加到新訂單列表耍群、判斷是否是新訂單义桂、從新訂單 id 列表中移除指定訂單 id 等方法。

接到新訂單提示有個(gè)新字蹈垢,點(diǎn)擊操作改訂單則表示已經(jīng)操作過(guò)不是新訂單了則去掉新字
地圖頁(yè)有新訂單則訂單氣泡上有個(gè)新字慷吊,點(diǎn)擊新字取消
OrderListModel.m:判斷是否是新訂單、通過(guò) id 添加到新訂單列表
OrderListModel.m:從新訂單 id 列表中移除指定訂單 id

應(yīng)用1 - 判斷是否是新訂單:isNewOrder

AcceptOrderTableViewCell 訂單列表 cell 判斷是否新訂單是否展示新字
地圖氣泡判斷是否新訂單是否展示新字

應(yīng)用2 - 添加到新訂單列表:addIntoNewOrderList

推送新訂單曹抬,通過(guò) id 添加到新訂單列表

應(yīng)用3 - 從新訂單 id 列表中移除指定訂單 id :removeFormNewOrderList

操作訂單溉瓶,從新訂單 id 列表中移除指定訂單 id
操作訂單,從新訂單 id 列表中移除指定訂單 id

舉例2:成都機(jī)場(chǎng)提示

場(chǎng)景2:定位成都的司機(jī),未報(bào)班狀態(tài)下訪(fǎng)問(wèn)首頁(yè)堰酿,新增“成都地區(qū)有新投運(yùn)機(jī)場(chǎng)”相關(guān)提示疾宏。

1.提示內(nèi)容:成都地區(qū)存在新投運(yùn)機(jī)場(chǎng),請(qǐng)您在接到相關(guān)訂單后及時(shí)跟乘客確認(rèn)目的地触创,以免走錯(cuò)機(jī)場(chǎng)坎藐。

2.展示邏輯:優(yōu)化上線(xiàn)后推送給定位為“成都”的司機(jī),司機(jī)非報(bào)班狀態(tài)下可見(jiàn)此提示哼绑,司機(jī)點(diǎn)擊“X”后隱藏不再展示橫幅岩馍。

3.注意2種情況:

第一種是同一部手機(jī)多次登錄同一個(gè)賬號(hào)或者同一部手機(jī)登錄多個(gè)賬號(hào)的時(shí)候,點(diǎn)擊 X 關(guān)閉提示語(yǔ)會(huì)記錄關(guān)閉次數(shù)抖韩,展示的時(shí)候需要判斷當(dāng)前賬號(hào)與關(guān)閉賬號(hào)是否是同一個(gè)賬號(hào)蛀恩。如果關(guān)閉次數(shù)大于0,判斷如果是同一個(gè)賬號(hào)則表示之前展示過(guò)且被關(guān)閉過(guò)則不需要展示茂浮,如果不是同一個(gè)賬號(hào)則表示關(guān)閉的是其他賬號(hào)赦肋,當(dāng)前賬號(hào)沒(méi)有被關(guān)閉過(guò)沒(méi)有關(guān)閉次數(shù)即未展示過(guò)或者展示過(guò)但未被關(guān)閉過(guò),這個(gè)時(shí)候需要展示励稳。

第二種情況是同一個(gè)賬號(hào)被多部手機(jī)登錄的時(shí)候,如果關(guān)閉次數(shù)等于0囱井,即第一次進(jìn)來(lái)頁(yè)面未報(bào)班的時(shí)候都展示驹尼。即使賬號(hào)在 A 手機(jī)登錄展示過(guò)被關(guān)閉過(guò),再在 B 手機(jī)上登錄一樣需要重新走 A 的邏輯庞呕,第一次進(jìn)來(lái)頁(yè)面未報(bào)班的時(shí)候還是需要展示提示語(yǔ)新翎,即這個(gè)緩存以手機(jī)為準(zhǔn),不以賬號(hào)為準(zhǔn)住练。

成都機(jī)場(chǎng)提示效果
機(jī)場(chǎng)提示語(yǔ)展示邏輯核心代碼
機(jī)場(chǎng)提示語(yǔ)展示邏輯核心代碼
機(jī)場(chǎng)提示語(yǔ)展示邏輯核心代碼
機(jī)場(chǎng)提示語(yǔ)頁(yè)面關(guān)閉按鈕回調(diào)
封裝的 BBXChengDuAirportTipsView
封裝的 BBXChengDuAirportTipsView

舉例3:訂單有個(gè)提示標(biāo)簽

場(chǎng)景3:如果是新用戶(hù)即首次下單的用戶(hù)地啰,對(duì)于貨件訂單且訂單備注包含類(lèi)型“手機(jī)數(shù)碼、數(shù)碼產(chǎn)品讲逛、大物件亏吝、其它、其他”等盏混,如果訂單狀態(tài)為上車(chē)了則不展示蔚鸥,如果是還沒(méi)有上車(chē)分2種情況,第一種是之前沒(méi)有展示過(guò)或者展示過(guò)沒(méi)有關(guān)閉則展示许赃,第二種是之前展示過(guò)且被關(guān)閉過(guò)則不展示提示標(biāo)簽止喷。

注意:

1.如果賬號(hào)在手機(jī) A 登錄有展示標(biāo)簽,點(diǎn)擊關(guān)閉后再在手機(jī) B 登錄發(fā)現(xiàn)也會(huì)有標(biāo)簽混聊,即緩存跟手機(jī)有關(guān)跟賬號(hào)沒(méi)有關(guān)系弹谁,兩個(gè)手機(jī)獨(dú)立的,相當(dāng)于各自都是第一次走邏輯互不影響。

2.如果賬號(hào)在手機(jī)上登錄有展示標(biāo)簽预愤,點(diǎn)擊關(guān)閉不展示標(biāo)簽沟于。這個(gè)時(shí)候 App 卸載重新安裝,新裝的 App 相當(dāng)于第一次重新走邏輯會(huì)展示標(biāo)簽鳖粟。

標(biāo)簽效果圖
判斷標(biāo)簽展示與否核心代碼
關(guān)閉標(biāo)簽回調(diào)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末社裆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子向图,更是在濱河造成了極大的恐慌泳秀,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榄攀,死亡現(xiàn)場(chǎng)離奇詭異嗜傅,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)檩赢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)吕嘀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贞瞒,你說(shuō)我怎么就攤上這事偶房。” “怎么了军浆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵棕洋,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我乒融,道長(zhǎng)掰盘,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任赞季,我火速辦了婚禮愧捕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘申钩。我一直安慰自己次绘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布撒遣。 她就那樣靜靜地躺著断盛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪愉舔。 梳的紋絲不亂的頭發(fā)上钢猛,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音轩缤,去河邊找鬼命迈。 笑死贩绕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的壶愤。 我是一名探鬼主播淑倾,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼征椒!你這毒婦竟也來(lái)了娇哆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤勃救,失蹤者是張志新(化名)和其女友劉穎碍讨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蒙秒,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勃黍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晕讲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片覆获。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瓢省,靈堂內(nèi)的尸體忽然破棺而出弄息,到底是詐尸還是另有隱情,我是刑警寧澤勤婚,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布摹量,位于F島的核電站,受9級(jí)特大地震影響蛔六,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜废亭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一国章、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧豆村,春花似錦液兽、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至粗恢,卻和暖如春柑晒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背眷射。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工匙赞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留佛掖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓涌庭,卻偏偏與公主長(zhǎng)得像芥被,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坐榆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容