iOS 本地存儲數據的幾種方式

寫在前面:iOS本地持久化存儲的路徑
Documents: 最常用的目錄瓣窄,存放重要的數據靶壮,iTunes同步時會備份該目錄
Library/Caches: 一般存放體積大从诲,不重要的數據,iTunes同步時不會備份該目錄
Library/Preferences: 存放用戶的偏好設置契耿,iTunes同步時會備份該目錄
tmp: 用于存放臨時文件瞒大,在程序未運行時可能會刪除該文件夾中的數據,iTunes同步時不會備份該目錄
存儲方式:NSUserDefaults搪桂、Plist透敌、NSKeyedArchiverSQLite3踢械、Core Data拙泽、KeychainFMDB


一裸燎、NSUserDefaults 方式存儲

1.1 寫入

 NSUserDefaults *login = [NSUserDefaults standardUserDefaults];
 [login setObject:self.passwordField.text forKey:@"token"];
 [login synchronize];

1.2 讀取

 NSUserDefaults *login = [NSUserDefaults standardUserDefaults];
 NSString *str = [login objectForKey:@"token"];

\color{#f5576c}{寫在后面:}
1.只能存儲OC常用數據類型(NSString顾瞻、NSDictionary、NSArray德绿、NSData荷荤、NSNumber等類型)而不能直接存儲自定義數據退渗。
2.鍵值對存儲,直接指定存儲類型蕴纳。


二会油、plist 方式存儲

2.1 寫入

#pragma mark - 保存到本地
- (void)saveToLocale {
    [self.view endEditing:YES];
    if (!self.nameField.text.length) {
        [TipUtils showToast:self.view message:@"應用名稱不能為空"];
        return;
    }
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:@"password.plist"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL Exists = [fileManager fileExistsAtPath:path];
    if (!Exists) {
        _serectArray = [[NSMutableArray alloc] init];
    } else {
        _serectArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
    }
    // 這里是修改更新數據
    for (int i=0;i <self.serectArray.count;i++) {
        if ([self.myPassword.timeID isEqualToString:self.serectArray[i][@"timeID"]]) {
            self.serectArray[i][@"name"] = self.nameField.text;
            [self.serectArray writeToFile:path atomically:YES];
            if ([self.serectArray writeToFile:path atomically:YES]) {
                [TipUtils showToast:self.view message:@"保存成功"];
                [self  performSelector:@selector(delayMethod) withObject:nil afterDelay:1.0f];
            } else {
                NSLog(@"保存失敗");
            }
            return;
        }
    }
    NSDictionary *dict = [NSDictionary dictionary];
    dict = @{@"timeID":[self getItemID], @"name":self.nameField.text};
    [self.serectArray addObject:dict];
    [self.serectArray writeToFile:path atomically:YES];
    if ([self.serectArray writeToFile:path atomically:YES]) {
        [TipUtils showToast:self.view message:@"保存成功"];
        [self  performSelector:@selector(delayMethod) withObject:nil afterDelay:1.0f];
        NSLog(@"存儲的數據有:%@",self.serectArray);
    } else {
        NSLog(@"保存失敗");
    }
}

#pragma mark - 延時函數
- (void)delayMethod {
    [self.navigationController popViewControllerAnimated:YES];
}

2.2 讀取

#pragma mark - 讀取數據
- (void)readDataFromPlist {
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:@"password.plist"];
NSLog(@"存儲路徑-%@",path);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL Exists = [fileManager fileExistsAtPath:path];
    if (!Exists) {
        _serectArray = [[NSMutableArray alloc] init];
    } else {
        _serectArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
    }
}

\color{#f5576c}{寫在后面:}
1.只能存儲OC常用數據類型(NSString、NSDictionary古毛、NSArray翻翩、NSData、NSNumber等類型)而不能直接存儲自定義模型對象稻薇。
· 如果想用對象嫂冻,只能再用明杰的框架進行字典轉模型了床绪。
· 或者想存儲自定義模型對象 -> 只能將自定義模型對象轉換為字典存儲断凶;
2.系統(tǒng)的plist文件,只能讀取谎痢,不行寫入案狠,自定義的可讀可寫
3.plist文件存儲的位置服傍,但一般存在Documents中
4.如果存儲圖片路徑的話,一定要存儲相對位置骂铁,因為每次啟動APP,plist文件的路徑就會變化吹零,自然圖片的位置也就變化了。


三拉庵、NSKeyedArchiver歸檔(NSCoding)
  • 歸檔解檔最大的好處在于可以存儲自定義對象數據
  • 歸檔解檔要注意ios版本
  1. 新建一個數據模型類Person
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCoding>
@property(nonatomic, copy) NSString *name;
@end
#import "Person.h"
@implementation Person
-(id)init {
    if (self == nil) {
        self = [super init];
    }
    return self;
}
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
    if (self = [super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
    }
    return self;
}
@end
  1. 新建一個歸檔解檔通用工具類ArchiveTools
#import <Foundation/Foundation.h>
@interface ArchiveTools : NSObject
+ (BOOL)archiveObject:(id)object prefix:(NSString *)prefix;
+ (id)unarchiveClass:(Class)class prefix:(NSString *)prefix;
+ (NSString *)getPathWithPrefix: (NSString *)prefix;
@end
#import "ArchiveTools.h"

@implementation ArchiveTools
#pragma mark - 歸檔解檔
+ (BOOL)archiveObject:(id)object prefix:(NSString *)prefix {
    if (!object) {
        return NO;
    }
    NSError *error;
    if (@available(iOS 11.0, *)) {
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object
                                             requiringSecureCoding:YES
                                                             error:&error];
        if (error)
            return NO;
        [data writeToFile:[self getPathWithPrefix:prefix] atomically:YES];
     } else {
         NSData*data = [NSKeyedArchiver archivedDataWithRootObject:object];
         [data writeToFile:[self getPathWithPrefix:prefix] atomically:YES];
     }
    return YES;
}
+ (id)unarchiveClass:(Class)class prefix:(NSString *)prefix {
    
    NSError *error;
    NSData *data = [[NSData alloc] initWithContentsOfFile:[self getPathWithPrefix:prefix]];
    //會調用對象的initWithCoder方法
    if (@available(iOS 11.0, *)) {
        id content = [NSKeyedUnarchiver unarchivedObjectOfClass:class fromData:data error:&error];
        if (error) {
            return nil;
        }
        return content;
    } else {
        id content = [NSKeyedUnarchiver unarchiveObjectWithData:data];
        return content;
    }
}
#pragma mark - 存放文件的路徑
+ (NSString *)getPathWithPrefix: (NSString *)prefix {
    // document路徑
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
    // 自定義一個文件夾
    NSString *filePathFolder = [documentPath stringsByAppendingPaths:@[@"archiveTemp"]].firstObject;
    if (![[NSFileManager defaultManager] fileExistsAtPath:filePathFolder]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:filePathFolder withIntermediateDirectories:YES attributes:nil error:nil];
    }
    NSString *path = [NSString stringWithFormat:@"%@/%@.archive",filePathFolder,prefix];
    NSLog(@"%@",path);
    return path;
}

3.調用使用

#import "ViewController.h"
#import "Person.h"
#import "ArchiveTools.h"
@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *person = [[Person alloc] init];
    person.name = @"I am Lili";
    // 存儲
    BOOL isSuccess = [ArchiveTools archiveObject:person prefix:NSStringFromClass(person.class)];
    NSLog(@"啦啦-%@",NSStringFromClass(person.class));
    if (isSuccess) {
        NSLog(@"存儲成功");
    } else {
        NSLog(@"存儲失敗");
    }
    // 讀取
    Person  *content = [ArchiveTools unarchiveClass:Person.class prefix:NSStringFromClass(Person.class)];
    NSLog(@"內容是-%@",content);
    NSLog(@"具體-%@", content.name);
    //刪除歸檔文件
    NSFileManager *defaultManager = [NSFileManager defaultManager];
    if ([defaultManager isDeletableFileAtPath:[ArchiveTools getPathWithPrefix:NSStringFromClass(Person.class)]]) {
        [defaultManager removeItemAtPath:[ArchiveTools getPathWithPrefix:NSStringFromClass(Person.class)] error:nil];
    }
}

四灿椅、SQLite3

1. 在項目中導入libsqlite3.0.tbd框架
2.使用數據庫

#import "ViewController.h"
#import <sqlite3.h>
@interface ViewController ()
@property(nonatomic, assign) int res;

@end

@implementation ViewController
{
    sqlite3 *db; // 聲明對象
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self createDB];
    [self createTable];
    [self insertData];
    [self selectData];
    // 關閉數據庫
    sqlite3_close(db);
}
#pragma mark - 數據庫相關操作
- (void)createDB {
    // 創(chuàng)建數據庫路徑
    NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:@"test.sqlite"];
    NSLog(@"數據庫路徑-%@",dbPath);
    // 創(chuàng)建或者打開數據庫
    const char *p = [dbPath UTF8String];
    int res = sqlite3_open(p, &db);
    self.res = res;
}
// 一、創(chuàng)建表格
- (void)createTable {
    if(self.res == SQLITE_OK) {
        NSLog(@"數據庫成功打開");
        NSString *sql = @"create table if not exists temps (t_id integer primary key autoincrement, t_name varchar(20))";
        if ([self execNoQueryWithSQL:sql]) {
            NSLog(@"創(chuàng)建表格成功");
        } else {
            NSLog(@"創(chuàng)建表格失敗");
        }
    } else {
        NSLog(@"數據庫未正常打開-%d",self.res);
    }
}
// 二名段、插入數據
- (void)insertData {
    if (self.res == SQLITE_OK) {
        NSString *insert_sql = @"insert into temps (t_name) values('banala')";
        if ([self execNoQueryWithSQL:insert_sql]) {
            NSLog(@"成功插入數據");
        } else {
            NSLog(@"插入數據失敗");
        }
    } else {
        NSLog(@"數據庫未正常打開-%d",self.res);
    }
}
// 三、刪除數據
- (void)deleteData {
    if (self.res == SQLITE_OK) {
        NSString *delete_sql = @"delete from temps where t_id=2";
        if ([self execNoQueryWithSQL:delete_sql]) {
            NSLog(@"成功刪除數據");
        } else {
            NSLog(@"刪除數據失敗");
        }
    } else {
        NSLog(@"數據庫未正常打開-%d",self.res);
    }
}
// 四泣懊、修改數據
- (void)updataData {
    if (self.res == SQLITE_OK) {
        NSString *update_sql = @"update temps set t_name='ios' where t_id=1";
        if ([self execNoQueryWithSQL:update_sql]) {
            NSLog(@"成功更新數據");
        } else {
            NSLog(@"更新數據失敗");
        }
    } else {
        NSLog(@"數據庫未正常打開-%d",self.res);
    }
}
// 五伸辟、查詢簡單數據,無參數
- (void)selectData {
    if (self.res == SQLITE_OK) {
//        NSString *select_sql1 = @"select * from temps where t_id=1";
       NSString *select_sql1 = @"select * from temps";
        sqlite3_stmt *stmt1 = [self execQueryWithSQL:select_sql1];
        while (sqlite3_step(stmt1) == SQLITE_ROW) {
            int t_id = sqlite3_column_int(stmt1, 0);
            const unsigned char *t_name = sqlite3_column_text(stmt1, 1);
            NSString *name = [NSString stringWithUTF8String:(char *)t_name];
            NSLog(@"%i %@",t_id,name);
        }
        // 釋放stmt statement
        sqlite3_finalize(stmt1);
    } else {
        NSLog(@"數據庫未正常打開-%d",self.res);
    }
}
// 六馍刮、查詢數據2 參數化的sql語句  查找 id>2 并且名字以p開頭的 用 信夫?占位
- (void)selectDataWithParams {
    if (self.res == SQLITE_OK) {
        int seachId2 = 1;
        NSString *seach_name = @"p%";
        NSString *seach_sql = @"select * from temps where t_id>? and t_name like ?";
        sqlite3_stmt *stmt6 = [self execQueryWithSQL:seach_sql andWithParams:@[[NSNumber numberWithInt:seachId2],seach_name]];
        
        //準備執(zhí)行(相當于點擊run query),執(zhí)行的時候是一行一行的執(zhí)行
        while (sqlite3_step(stmt6) == SQLITE_ROW) {
            //按照當前列的類型選數據,列數從0開始
            int t_id = sqlite3_column_int(stmt6, 0);
            const unsigned char *t_name = sqlite3_column_text(stmt6, 1);
            NSString *name = [NSString stringWithUTF8String:(char*)t_name];
            NSLog(@"..>>>>>>...%i %@",t_id,name);
        }
        sqlite3_finalize(stmt6);
    } else {
        NSLog(@"數據庫未正常打開-%d",self.res);
    }
}

#pragma mark - 執(zhí)行除查詢以外的操作
- (BOOL)execNoQueryWithSQL:(NSString *)sql {
    /*
     執(zhí)行
     參數1:sqlite3 對象
     參數2:c形式的 sql語句
     參數3:回調函數
     參數4:回調函數的參數
     參數5:錯誤信息(可以char類型指針接受錯誤信息卡啰,用來查錯使用)
     */
    char *error;
    int result =  sqlite3_exec(db, [sql UTF8String], NULL, NULL, &error);
    if (result == SQLITE_OK) {
        return YES;
    } else {
        NSLog(@"%s",error);
    }
    return NO;
}
#pragma mark - 返回查詢結果集静稻,無參數
-(sqlite3_stmt *)execQueryWithSQL:(NSString *)sql {
    sqlite3_stmt *stmt;
    /*
     準備執(zhí)行查詢的sql語句 (相當于把查詢語句寫好)
     參數3:sql語句長度,通常用-1表示(系統(tǒng)會自動計算)匈辱,也可以用strlength函數計算
     參數4:sql_stmt對象 (執(zhí)行的對象)
     參數5:未執(zhí)行的sql語句
     */
    int pre_res = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
    if (pre_res == SQLITE_OK) {
        return stmt;
    }
    return NULL;
}
#pragma mark - 返回查詢結果集m振湾,有參數
-(sqlite3_stmt *)execQueryWithSQL:(NSString *)sql andWithParams:(NSArray *)params{
    sqlite3_stmt *stmt;
    int pre_res = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
    if (pre_res == SQLITE_OK) {
        if (params!=nil) {
            for (int i = 0 ; i<params.count; i++) {
                id obj = params[i];
                //綁定的數據類型可能為NSString或者NSNumber,或者數據為空亡脸,分別判斷
                if (obj == nil) {
                    // 數據為空
                    sqlite3_bind_null(stmt, i+1);
                } else if ([obj respondsToSelector:@selector(objCType)]) {
                    //當前的綁定的數據類型位NSNumber
                    //NSNumber判斷包裝的是int押搪?longInt树酪?shortInt?float?double?
                    /*
                     strstr(參數1,參數2) (strstr() c中函數搜索一個字符串在另一個字符串中的第一次出現大州,則該函數返回第一次匹配的字符串的地址续语,找不到返回NULL)
                     判斷參數1中的字符在參數2的字符串char*中出現的索引
                     [obj objCType] 如果obj是int返回字符串i
                     */
                    if (strstr("ilsILS", [obj objCType])) {
                        /*
                         綁定參數 如果有where
                         參數1:sqlite_stmt對象 (statement結果集)
                         參數2:占位符索引 從1開始
                         參數3:替代占位符的真實參數
                         */
                        sqlite3_bind_int(stmt, i+1, [obj intValue]);
                    } else if (strstr("fdFD", [obj objCType])){
                        sqlite3_bind_double(stmt, i+1, [obj doubleValue]);
                    } else {
                        stmt = nil;
                    }
                } else if ([obj respondsToSelector:@selector(UTF8String)]) {
                    //當前的綁定的數據類型為NSString 判斷是否有UTF8String方法
                    //用bind替換占位符 索引從1開始
                    sqlite3_bind_text(stmt, i+1, [obj UTF8String], -1, NULL);
                } else {
                    stmt = nil;
                }
            }
        }
        return stmt;
    }
    return NULL;
}
@end


五、Core Data

Core Data是iOS5之后才出現的一個框架厦画,提供了直接使用SQLite數據庫的大部分靈活性疮茄,它提供了對象-關系映射(ORM)的功能,即能夠將OC對象轉化成數據根暑,保存在SQLite數據庫文件中力试,也能夠將保存在數據庫中的數據還原成OC對象,通過CoreData管理應用程序的數據模型购裙,可以極大程度減少需要編寫的代碼數量懂版!

  • 廢話不多說,直接上代碼躏率!
//創(chuàng)建數據庫
- (void)createSqlite{
    
    //1躯畴、創(chuàng)建模型對象
    //獲取模型路徑
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreData__" withExtension:@"momd"];
    //根據模型文件創(chuàng)建模型對象
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    
    
    //2、創(chuàng)建持久化存儲助理:數據庫
    //利用模型對象創(chuàng)建助理對象
    NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    
    //數據庫的名稱和路徑
    NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *sqlPath = [docStr stringByAppendingPathComponent:@"coreData.sqlite"];
    NSLog(@"數據庫 path = %@", sqlPath);
    NSURL *sqlUrl = [NSURL fileURLWithPath:sqlPath];
    
    NSError *error = nil;
    //設置數據庫相關信息 添加一個持久化存儲庫并設置存儲類型和路徑薇芝,NSSQLiteStoreType:SQLite作為存儲庫
    [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:nil error:&error];
    
    if (error) {
        NSLog(@"添加數據庫失敗:%@",error);
    } else {
        NSLog(@"添加數據庫成功");
    }
    
    //3蓬抄、創(chuàng)建上下文 保存信息 操作數據庫
    
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    
    //關聯(lián)持久化助理
    context.persistentStoreCoordinator = store;
    
    _context = context;
    
    
}

六、Keychain(SQLite API進行封裝的庫)
  • Keychain存儲也并不是絕對安全夯到,越獄設備可以拿到
  • 程序卸載還存在
  • 對于每個應用來說嚷缭,keychain都有兩個訪問區(qū),私有區(qū)和公共區(qū)
    私有區(qū)是一個閉合的存儲區(qū)域耍贾,每個應用只能操作自己的私有區(qū)阅爽,本應用存儲的任何數據對其他程序不可見,其他程序也沒有權限訪問這個私有區(qū)荐开。(可以理解為存在鑰匙串的沙盒)付翁。
    公共區(qū),apple提供給同一個開發(fā)者賬號開發(fā)的多個app之間的一個數據共享模塊』翁現在只局限于同一個開發(fā)者賬號下的不同app之間數據共享百侧。這個區(qū)域是獨立于私有區(qū)的另外一個數據存儲空間。實現多個應用間共同訪問一些數據能扒。
    缺陷:Keychain變化的幾種情況
    1.越獄機
    2.部分操作系統(tǒng)bug
    3.應用卸載后升級iOS系統(tǒng)

七佣渴、第三方FMDB,BGFMDB
  • 下載FMDB框架初斑,程序導入sqlite3.0框架
  • 廢話不多說辛润,上代碼
#import "ViewController.h"
#import "FMDB.h"
#import "Person.h"
@interface ViewController ()
{
    FMDatabase *db;
}
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self createDB];
    [self deleteData];
    [self queryData];
}

-(void)createDB {
   // 1.
    NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *dbPath = [docuPath stringByAppendingPathComponent:@"test.db"];
    NSLog(@"!!!dbPath = %@",dbPath);
    //2.創(chuàng)建對應路徑下數據庫
    db = [FMDatabase databaseWithPath:dbPath];
    //3.在數據庫中進行增刪改查操作時,需要判斷數據庫是否open
    [db open];
    if (![db open]) {
        NSLog(@"db open fail");
        return;
    }
    //4.數據庫中創(chuàng)建表(可創(chuàng)建多張)
    NSString *sql = @"create table if not exists t_student ('ID' INTEGER PRIMARY KEY AUTOINCREMENT,'name' TEXT NOT NULL, 'phone' TEXT NOT NULL,'score' INTEGER NOT NULL)";
    //5.執(zhí)行更新操作 此處database直接操作见秤,不考慮多線程問題频蛔,多線程問題灵迫,用FMDatabaseQueue 每次數據庫操作之后都會返回bool數值,YES晦溪,表示success瀑粥,NO,表示fail,可以通過 @see lastError @see lastErrorCode @see lastErrorMessage
    BOOL result = [db executeUpdate:sql];
    if (result) {
        NSLog(@"create table success");
        
    }
    [db close];
}
- (void)insertData {
    [db open];
    // 插入
    BOOL result2 = [db executeUpdate:@"insert into 't_student'(ID,name,phone,score) values(?,?,?,?)" withArgumentsInArray:@[@113,@"x3",@"13",@53]];
    if (result2) {
        NSLog(@"insert into 't_studet' success");
        [self showAlertWithTitle:@"insert  success" message:nil person:nil];
    } else {
        [self showAlertWithTitle:[db lastError].description message:nil person:nil];
    }
    [db close];
}
-(void)deleteData{
    [db open];
    BOOL result = [db executeUpdate:@"delete from 't_student' where ID = ?" withArgumentsInArray:@[@153]];
    if (result) {
        NSLog(@"delete from 't_student' success");
        [self showAlertWithTitle:@"delete  success" message:nil person:nil];
    } else {
        [self showAlertWithTitle:[db lastError].description message:nil person:nil];
    }
    [db close];
    
}
-(void)updateData{
    [db open];
    BOOL result = [db executeUpdate:@"update 't_student' set ID = ? where name = ?" withArgumentsInArray:@[@153,@"x3"]];
    if (result) {
        NSLog(@"update 't_student' success");
        [self showAlertWithTitle:@"update  success" message:nil person:nil];
    } else {
        [self showAlertWithTitle:[db lastError].description message:nil person:nil];
    }
    [db close];
}
-(void)queryData {
    [db open];
    FMResultSet *result = [db executeQuery:@"select * from 't_student' where ID = ?" withArgumentsInArray:@[@153]];
    NSMutableArray *arr = [NSMutableArray array];
    while ([result next]) {
        Person *person = [Person new];
        person.ID = [result intForColumn:@"ID"];
        person.name = [result stringForColumn:@"name"];
        person.phone = [result stringForColumn:@"phone"];
        person.score = [result intForColumn:@"score"];
        [arr addObject:person];
        NSLog(@"從數據庫查詢到的人員 %d-%@-%@-%d",person.ID, person.name,person.phone,person.score);
        [self showAlertWithTitle:@"query  success" message:nil person:person];
        
    }
}
-(void)showAlertWithTitle:(NSString *)title
                  message:(NSString *)message
                   person:(Person *)person
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"sure" style:UIAlertActionStyleDefault handler:nil];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.text = person.name ? person.name : @"other";
    }];
    [alert addAction:cancelAction];
    [self presentViewController:alert animated:YES completion:^{
      }];
}
@end
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末三圆,一起剝皮案震驚了整個濱河市狞换,隨后出現的幾起案子,更是在濱河造成了極大的恐慌舟肉,老刑警劉巖修噪,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異路媚,居然都是意外死亡黄琼,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門整慎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脏款,“玉大人,你說我怎么就攤上這事裤园〕肥Γ” “怎么了?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵拧揽,是天一觀的道長剃盾。 經常有香客問我,道長淤袜,這世上最難降的妖魔是什么痒谴? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮铡羡,結果婚禮上积蔚,老公的妹妹穿的比我還像新娘。我一直安慰自己蓖墅,他們只是感情好库倘,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布临扮。 她就那樣靜靜地躺著论矾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杆勇。 梳的紋絲不亂的頭發(fā)上贪壳,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音蚜退,去河邊找鬼闰靴。 笑死彪笼,一個胖子當著我的面吹牛,可吹牛的內容都是我干的蚂且。 我是一名探鬼主播配猫,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼杏死!你這毒婦竟也來了泵肄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤淑翼,失蹤者是張志新(化名)和其女友劉穎腐巢,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體玄括,經...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡冯丙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了遭京。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胃惜。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖洁墙,靈堂內的尸體忽然破棺而出蛹疯,到底是詐尸還是另有隱情,我是刑警寧澤热监,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布捺弦,位于F島的核電站,受9級特大地震影響孝扛,放射性物質發(fā)生泄漏列吼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一苦始、第九天 我趴在偏房一處隱蔽的房頂上張望寞钥。 院中可真熱鬧,春花似錦陌选、人聲如沸理郑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽您炉。三九已至,卻和暖如春役电,著一層夾襖步出監(jiān)牢的瞬間赚爵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冀膝,地道東北人唁奢。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像窝剖,于是被迫代替她去往敵國和親麻掸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350