【IOS學習基礎】歸檔和解檔


一、歸檔介紹

  1.歸檔是指用某種格式來保存一個或多個對象,以便以后還原這些對象的過程。歸檔是將數據持久化的一種方式(所謂數據持久化,就是指在IOS開發過程中,將數據保存到本地,能夠讓程序的運行更加流暢)。

  2.想要歸檔的數據對象,需要遵守NSCoding協議,並且該對象對應的類必須提供encodeWithCoder:initWithCoder:方法。

  3.歸檔就是將臨時數據保存成本地文件。

  4.歸檔的缺點:歸檔的形式來保存數據,只能一次性歸檔保存以及一次性解壓。所以只能針對小量數據,而且對數據操作比較笨拙,即如果想改動數據的某一小部分,還是需要解壓整個數據或者歸檔整個數據。

二、XML歸檔

  1.局限:數據類型只支持 NSString、NSDictionary、NSArayy、NSData、NSNumber(如果你想的話,可以將基本數據類型轉換為NSNumber再進行歸檔)。

  2.比較方便,設置好歸檔路徑,一句話歸檔,一句話解檔。

  3.歸檔文件格式:一般保存.plist文件。

/**** NSString和NSMutableString XML歸解檔 ****/ NSString *str = @"hello world"; NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"hello.txt"]; // atomically:這個參數意思是如果為YES,則保證文件的寫入原子性。就是說會先創建一個臨時文件,直到文件內容寫入成功再導入到目標文件里.如果為NO,則直接寫入目標文件里.
[str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil]; // 這里會覆蓋原來的內容
[@"hello world 2" writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil]; NSString *str2 = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
/**** NSData和NSMutableData XML歸解檔 ****/
// 任何對象都可以轉化為NSData
NSData *data = [@"hello world" dataUsingEncoding:NSUTF8StringEncoding]; NSString *path2 = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"data.txt"]; //歸檔
[data writeToFile:path2 atomically:YES]; //解檔
[NSData dataWithContentsOfFile:path2];
/**** NSArray及NSMutableArray XML歸解檔 ****/
NSArray *array = @[@"test",@"test2"];
NSString *path3 = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"array.plist"];
// 歸檔 [array writeToFile:path3 atomically:YES]; // 解 NSArray *array = [NSArray arrayWithContentsOfFile:path3];
/**** NSArray XML歸解檔 ****/ NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"one",@"1",@"two",@"2", nil]; NSString *path4 = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"dic.plist"]; // 歸檔
[dic writeToFile:path4 atomically:YES]; // 解檔
NSDictionary *ddic = [NSDictionary dictionaryWithContentsOfFile:path3];

三、NSKeyedArchiver歸檔

  1.將各種類型的對象存儲到文件中,而且不僅僅是字符串、數組和字典類型,有一種更靈括的方法。就是利用NSKeyedArchiver類創建帶鍵(keyed)的檔案來完成。實現對我們自定義的類進行歸檔。

  2.序列化與反序列化:將一個Objective-C對象轉換成NSData的操作叫做對象的序列化;而將一個NSData轉換成Objective-C對象的操作叫做對象的反序列化。一個Objective-C對象需要通過實現NSCoding協議以便支持序列化與反序列化

  3.模擬場景:有一個學生類,學生擁有三個屬性nameagebook(一本書),其中book對應Book類,Book類中擁有一個屬性bookName,歸檔一個數組,數組中有兩個student對象。

  Student類


#import <Foundation/Foundation.h>
#import "Book.h"

@interface Student : NSObject<NSCoding> @property (nonatomic,copy)NSString *name; @property (nonatomic,assign)int age; // 除Student類之外,這里有一個自定義類型Book,所以Book類也需要實現NSCoding協議,從而進行歸檔
@property (nonatomic,strong)Book *book; @end
#import "Student.h"

@implementation Student -(void)encodeWithCoder:(NSCoder *)aCoder { // 歸檔姓名(NSString 對象)
    [aCoder encodeObject:self.name forKey:@"name"]; // 歸檔年齡(基本數據類型,如果是其它基本數據類型調用相應的encode方法)
    [aCoder encodeInt:self.age forKey:@"age"]; // 歸檔自定義類(Book)
    [aCoder encodeObject:self.book forKey:@"book"]; } -(instancetype)initWithCoder:(NSCoder *)aDecoder { if(self = [super init]) { //歸檔的key 寫的什么 對應屬性解檔key就寫什么
        self.name = [aDecoder decodeObjectForKey:@"name"]; self.age = [aDecoder decodeInt32ForKey:@"age"]; self.book = [aDecoder decodeObjectForKey:@"book"]; } return self; } @end

 同樣的,Book類也要實現<NSCoding>協議並重寫相應的兩個方法。

 NSKeyedArchiver歸檔實現代碼:

// 這里student、book對象初始化的代碼就不列了
NSArray *stuArr = @[stu1,stu2]; if ([NSKeyedArchiver archiveRootObject:stuArr toFile:path5]) { NSLog(@"寫入成功"); } NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithFile:path5];

 如此,便可以實現自定義對象的歸檔和解檔了。

四、NSUserDefaults

  1.NSUserDefaults是一個單例類,如它的名字一樣,用於永久保存一些用戶對於應用程序的配置之類的簡單數據,其簡單而又實用

  2.NSUserDefaults支持的數據類型同XML歸檔一樣,僅僅用於保存一些程序配置信息的話完全是可以勝任的。

// 保存
NSString *passWord = @"88888888"; NSUserDefaults *user = [NSUserDefaults standardUserDefaults]; [user setObject:passWord forKey:@"passWord"]; // 通過存儲時候key取出相應的value
NSString *passWord = [ user objectForKey:@"passWord"];

  3.當然,NSUserDefaults也可以存儲自定義類,同NSKeyedArchiver歸檔相似,為自定義類實現<NSCoding>協議,然后

// 將student類型變為NSData類型 (這里采用NSKeyedArchiver中的例子Student為例)
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
// NSUserDefaults是支持NSData類型
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"student"]; 

五、由sqlite到FMDB

  1.使用sqlite之前需要了解一下基本的一些sql語句,很簡單,學會建表、增刪改查的語句就行了。(學習的話這里推薦火狐瀏覽器下的sqlite組件)

  

  2.使用:在工程中導入包“libsqlite3.dylib”,在類中導入頭文件#import <sqlite3.h>

  

  Xcode7注意了,當你去導入sqlite3.dylib的時候(其實那兩個.tbd文件就是以前老版本的替代了),你會發現根本找不到這個包,因為這個包自xcode7之后就被蘋果隱藏掉了

  如果你想要使用老版本的,請繼續下面的操作。

  當點擊“+”彈出窗口之后,選擇“add other”,快捷鍵 CMD+Shift+G (Go to the folder),輸入/usr/lib后,進入隱藏的界面,在文件目錄下找到,然后添加你需要的 *.dylib,如libsqlite3.dylib文件。

  

  3.sqlite使用,這里講一下我之前做的一個增刪改查的demo,下面貼上代碼

 User類:

#import <Foundation/Foundation.h>

@interface User : NSObject @property (nonatomic,retain)NSData *icon; // 頭像
@property (nonatomic,copy)NSString *name; // 名字
@property (nonatomic,copy)NSString *phone;  // 電話號碼
@property (nonatomic,assign)int age; // 年齡
 @property (nonatomic,assign)NSInteger ID; @end

UserDBManager類

//
// UserDBManager.h // Sqlite3基礎操作 //
// Created by silence on 15-8-15. // Copyright (c) 2015年 hawode06. All rights reserved. // 
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#import "User.h"

#define insert @"INSERT"

@interface UserDBManager : NSObject // 插入數據
-(BOOL)insertUser:(User *)user; // 刪除數據
-(BOOL)delePerson:(NSInteger)idd; // 修改數據
-(BOOL)updatePerson:(User *)User; // 查詢所有
-(NSArray *)queryUser; // 通過姓名查詢用戶
-(NSArray *)searchWithName:(NSString *)str; @end

//
// UserDBManager.m // Sqlite3基礎操作 //
// Created by silence on 15-8-15. // Copyright (c) 2015年 hawode06. All rights reserved. // 
#import "UserDBManager.h"

@interface UserDBManager () @property (nonatomic,copy)NSString *dbPath; @property (nonatomic,assign)sqlite3 *dataBase; @end

@implementation UserDBManager -(BOOL)openDB { NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *dbPath = [path stringByAppendingPathComponent:@"user.db"]; NSLog(@"%@",dbPath); NSFileManager *fm = [NSFileManager defaultManager]; if([fm fileExistsAtPath:dbPath]) { //如果存在就打開
        bool result = sqlite3_open([dbPath UTF8String], &_dataBase) == SQLITE_OK; if (result) { return YES; } else { sqlite3_close(_dataBase); return NO; } } else { //打開數據庫 返回值sqlite_ok 代表打開成功
        if (sqlite3_open([dbPath UTF8String], &_dataBase) == SQLITE_OK) { NSString *sql = @"create table if not exists \"User\"(\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,\"name\" varchar,\"phone\" varchar,\"age\" INTEGER NOT NULL DEFAULT 1,\"image\" blob)";            //執行創建表的sql語句
            sqlite3_stmt *stateMent; //解析sql語句 第一個 數據庫變量 第二個sql語句 sql語句的長度 -1代表自動計算 stetement變量
            int pResult =  sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &stateMent, nil); //解析sql 語句失敗
            if (pResult != SQLITE_OK) { NSLog(@"創建表失敗"); } else { //執行sql 語句 成功
                if (sqlite3_step(stateMent) == SQLITE_DONE) { NSLog(@"創建表成功"); } else { NSLog(@"創建表失敗"); } } //釋放statement
 sqlite3_finalize(stateMent); return YES; } else { sqlite3_close(_dataBase); return NO; } } return YES; } -(BOOL)insertUser:(User *)user { if ([self openDB]) { NSString *addSql = @"insert into User (name,phone,age,image) values (?,?,?,?)"; sqlite3_stmt *stateMent; //解析sql語句 第一個 數據庫變量 第二個sql語句 sql語句的長度 -1代表自動計算 stetement變量
        int result = sqlite3_prepare_v2(_dataBase, [addSql UTF8String], -1, &stateMent, nil); //給sql語句里的’?‘ 賦值 第一個參數是statement 第二個是‘?’的位置 以1開頭 //姓名
        sqlite3_bind_text(stateMent, 1, [user.name UTF8String], -1, SQLITE_TRANSIENT); //電話
        sqlite3_bind_text(stateMent, 2, [user.phone UTF8String], -1, SQLITE_TRANSIENT); //年齡
        sqlite3_bind_int(stateMent, 3, user.age); //頭像
        sqlite3_bind_blob(stateMent, 4, [user.icon bytes], (int)user.icon.length, nil); if (result == SQLITE_OK) { //執行sql 語句 成功
            if (sqlite3_step(stateMent) == SQLITE_DONE) { NSLog(@"插入成功"); } else { NSLog(@"插入失敗"); } } //釋放statement
 sqlite3_finalize(stateMent); //關閉數據庫
 sqlite3_close(_dataBase); return YES; } return NO; } -(BOOL)delePerson:(NSInteger)idd { if ([self openDB]) { NSString *deleSql = [NSString stringWithFormat:@"delete from User where id = %ld",idd];  // 通過id刪除user表中的用戶數據
        sqlite3_stmt *stateMent; int result = sqlite3_prepare_v2(_dataBase, [deleSql UTF8String], -1, &stateMent, nil); if (result == SQLITE_OK) { //執行sql 語句 成功
            if (sqlite3_step(stateMent) == SQLITE_DONE) { NSLog(@"刪除成功"); } else { NSLog(@"刪除失敗"); } } //釋放statement
 sqlite3_finalize(stateMent); //關閉數據庫
 sqlite3_close(_dataBase); return YES; } return NO; } -(NSArray *)queryUser { NSMutableArray *arr; if ([self openDB]) { arr = [NSMutableArray arrayWithCapacity:0]; NSString *sql = @"select * from User";            //sql 語句:查詢User表中的所有數據
        sqlite3_stmt *statement; //解析sql語句 第一個 數據庫變量 第二個sql語句 sql語句的長度 -1代表自動計算 stetement變量
        int pResult =  sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &statement, nil); //解析sql語句成功
        if (pResult == SQLITE_OK) { while (sqlite3_step(statement) == SQLITE_ROW) { User *user = [[User alloc] init]; int num = sqlite3_column_int(statement, 0); char *cName = (char *)sqlite3_column_text(statement, 1); char *cPhone = (char *)sqlite3_column_text(statement, 2); int age = sqlite3_column_int(statement, 3); char *iconBytes = (char *)sqlite3_column_blob(statement, 4); NSInteger iconDataLen = sqlite3_column_bytes(statement, 4); user.name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding]; user.phone = [NSString stringWithCString:cPhone encoding:NSUTF8StringEncoding]; user.age = age; user.icon = [NSData dataWithBytes:iconBytes length:iconDataLen]; user.ID = num; [arr addObject:user]; } //釋放statement
 sqlite3_finalize(statement); } //關閉數據庫
 sqlite3_close(_dataBase); } return arr; } -(NSArray *)searchWithName:(NSString *)str { NSMutableArray *arr; if ([self openDB]) { arr = [NSMutableArray arrayWithCapacity:0]; NSString *sql = [NSString stringWithFormat:@"select * from User where name like '%%%@%%'",str]; NSLog(@"sql語句:%@",sql); sqlite3_stmt *statement; //解析sql語句 第一個 數據庫變量 第二個sql語句 sql語句的長度 -1代表自動計算 stetement變量
        int pResult =  sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &statement, nil); //解析sql語句成功
        if (pResult == SQLITE_OK) { while (sqlite3_step(statement) == SQLITE_ROW) { User *user = [[User alloc] init]; int num = sqlite3_column_int(statement, 0); char *cName = (char *)sqlite3_column_text(statement, 1); char *cPhone = (char *)sqlite3_column_text(statement, 2); int age = sqlite3_column_int(statement, 3); char *iconBytes = (char *)sqlite3_column_blob(statement, 4); NSInteger iconDataLen = sqlite3_column_bytes(statement, 4); user.name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding]; user.phone = [NSString stringWithCString:cPhone encoding:NSUTF8StringEncoding]; user.age = age; user.icon = [NSData dataWithBytes:iconBytes length:iconDataLen]; user.ID = num; [arr addObject:user]; } NSLog(@"數組%@",arr); //釋放statement
 sqlite3_finalize(statement); } //關閉數據庫
 sqlite3_close(_dataBase); } return arr; } @end

// 修改用戶數據的好像當時懶得做,並沒有實現那個方法,看懂了另外幾個增、查、刪的實現也就差不多了,基本操作數據庫的流程都一樣,只是執行不同的sql語句而已。
 

  4.界面的代碼就不貼了,大致是這樣的

 

 

 通過前往文件夾,可以看到目錄下面有一個后綴名為db的文件

  

打開之后,也可以看到其中的三條數據(這里我使用的是mac山觀點SQLite.app軟件)

本來准備把FMDB的使用介紹一起寫在這里的,但想了一下,還是待以后再寫在三方庫學習歸類里面吧,多復習總是對自己有好處的。(FMDB是經過別人封裝好的數據庫操作三方庫,使用起來非常簡單)

 

六、coreData

  還沒去了解如何使用,改天再自己學一下再寫吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM