国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > iOS > 正文

關于iOS GYDataCenter本地數據庫解決方案的那些事兒--上卷

2019-11-09 18:56:39
字體:
來源:轉載
供稿:網友

       之前提到到前端處理數據線程的解決方案,這里有需要到數據的本地存儲,數據持久最好的方式首選數據庫。那現在在我們的面前的有兩種選擇,一種是apple的coredata,另外一種就是采用FMDB。我的主觀反應是,我首推的是FMDB,FMDB的靈活性能更強,適用于多種場景,在數據處理上,可以通過選擇不同的SQL語句,達到更好的效果。在FMDB的基礎上,還有一個更便利的框架--GYDataCenter。

這里就從一個比較完整的數據模型的創建來講解著一個解決方案。

這個解決方案大體上分為:數據模型(數據表),數據操作(邏輯運算)和數據遷移,其實就是數據的增刪查改,對于不是很了解的SQL語句的開發者來說,這個在方便不過了,在下面的內容里面也穿插講解一下md5和基礎用戶存儲的一些解決方案。

主要內容:

1.用戶的概念2.如何創建一個數據庫和庫表3.如何進行增刪查改

本文主要講解1 、 2兩個點。

1.用戶的概念

      首先,我們必須明白有用戶群體就擁有商機,我在給一些項目做維護的時候,很多開發者喜歡用 NSUserDefaults去存儲一些用戶或者登錄者的基本信息,甚至去存儲支付類的私鑰或者公鑰。個人不是很提倡使用這個種方法,一方面考慮到安全性的問題,一方面代碼要寫得高大上一丟丟。   Apple提供了一個加密類給開發者提供--NSKeyedArchiver,其實就是一個歸檔的過程,保存用戶信息就是創建一個檔案,很多開發者覺得這個類用起來比較麻煩,所以很多人都不忽略它的存在。   我們來看看這個類到底怎么用,我們創建一個user基礎信息的模型,從網絡請求回來的數據轉換成模型就比較容易操作了,這個是時候,一般用戶的基本信息都是不作修改的,所以在創建的時候我們可以將用戶的屬性設置成readonly(只是建議需要根據實際的情況去決定)。創建一個QYJUserInfo的model,在.h文件里面去定義需要的字段。
#import <Foundation/Foundation.h>@interface QYJUserInfo : NSObject <NSCopying>{    NSString *_id;}/** * 賬號 */@PRoperty (nonatomic, copy) NSString *username;/** * 密碼 */@property (nonatomic, copy) NSString *passWord;/** * 郵箱 */@property (nonatomic, copy) NSString *email;/** * 刪除標識,未刪:0,已刪:1 */@property (nonatomic, copy) NSString *deleted;/** * 用戶ID */@property (nonatomic, copy) NSString *userID;/** * 中文名 */@property (nonatomic, copy) NSString *cname;/** * 聯系手機號碼 */@property (nonatomic, copy) NSString *phone;/** * 用戶類型 */@property (nonatomic, copy) NSString *type;/** * 英文名 */@property (nonatomic, copy) NSString *ename;/** * 創建時間 */@property (nonatomic, copy) NSString *created_dt;/** * 更新時間 */@property (nonatomic, copy) NSString *updated_dt;/** * 基礎方法 *//* @method toModelWithDictionary: @abstrac 字典轉模型,用戶類型一般只處理一個 @discussion 字典轉模型 @param dict (NSDictionary *) @result QYJUserInfo 對象 */+ (instancetype)toModelWithDictionary:(NSDictionary *)dict;/* @method toDictionary @abstrac 轉字典 @discussion 轉字典 @param No param @result NSDictionary */- (NSDictionary *)toDictionary;/* @method getMD5 @abstrac 將對象的值和屬性名轉成字符串MD5 @discussion 將對象的值和屬性名轉成字符串MD5 @param No param @result NSString */- (NSString *)getMD5;/* @method saveObjectToLocal @abstrac 保存對象到本地 @discussion 保存對象到本地 @param No param @result BOOL 保存結果 */- (BOOL)saveObjectToLocal;/* @method localUserInfo: @abstrac 查詢本地用戶信息,一般做自動登錄的用戶只允許有一個 @discussion 查詢本地用戶信息 @param No param @result QYJUserInfo對象 */+ (instancetype)localUserInfo;/* @method deleteUserInfo: @abstrac 刪除本地存儲的用戶數據,在用戶點擊出按鈕的時候調用 @discussion 刪除本地存儲的用戶數據,在用戶點擊出按鈕的時候調用 @param No param @result No return */+ (void)deleteUserInfo;/* @method compare: @abstrac 比較大小 @discussion 比較大小 @param QYJUserInfo對象 @result NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending */- (NSComparisonResult)compare:(QYJUserInfo *)otherObject;@end

      在.m的文件中我們要去實現我們聲明的文件。

#import "QYJUserInfo.h"//runtime 需要引用的頭文件#import <objc/runtime.h>#import "NSString+MD5.h"// 保存的Key static NSString *const localSaveKey = @"com.userInfo.qyj";@implementation QYJUserInfo@synthesize userID = _id;#pragma mark - NSCopying- (id)copyWithZone:(NSZone *)zone {    Class modelClass = [self class];    QYJUserInfo *object = [[modelClass alloc] init];        NSArray *propertyName = [modelClass getPropertyNames];    NSLog(@"%@", propertyName);    for (NSString *property in propertyName) {        [object setValue:[self valueForKey:property] forKey:property];    }        return object;}+ (NSArray *)getPropertyNames {    NSMutableArray *names = @[].mutableCopy;    u_int count;    objc_property_t *properties  = class_copyPropertyList(self, &count);        for (int i=0; i<count; i++) {        objc_property_t property = properties[i];         NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];                [names addObject:propertyName];            }    //釋放    free(properties);        return names;}#pragma mark - public Method+ (instancetype)toModelWithDictionary:(NSDictionary *)dict {    QYJUserInfo *userInfo = [[QYJUserInfo alloc] init];    /**     *這里需要注意的是 id 在OC中是一個系統的特殊符號,所以用@synthesize userID = _id     *來處理setValuesForKeysWithDictionary中對于id的轉換。     */    [userInfo setValuesForKeysWithDictionary:dict];    return userInfo;}- (NSDictionary *)toDictionary {        NSMutableDictionary *dict = @{}.mutableCopy;    NSArray *propertyName = [[self class] getPropertyNames];        for (NSString *property in propertyName) {        id value = [self valueForKey:property];        //這里字典不能傳入一個nil的對象,這里就加一個判斷        //這里只存在字符串類型的類型的數據,故這樣判段,如果存在多種類型著要注意基礎類型int一類的數據        [dict setValue:value ? value : @""  forKey:property];    }        return dict;}- (NSString *)getMD5 {        NSString *mdStringMD5 = @"";    NSArray *propertyName = [[self class] getPropertyNames];    for (NSString *property in propertyName) {        id value = [self valueForKey:property];        /**         *如果是需要和后臺交互的,這里要和后臺約定好MD5排列的順序         *只要字段的排列順序不一樣,生成的MD5也不一樣,         *OC的字典轉String的順序和java中toString的順序有可能不相同,導致數據驗證失敗         *字符串中字段順序就是.h文件中的聲明的順序一致         */        if (value) {            mdStringMD5 = [mdStringMD5 stringByAppendingString:[NSString stringWithFormat:@"%@%@", propertyName, value]];        }    }    return mdStringMD5.MD5;}- (BOOL)saveObjectToLocal {    //創建文檔的key和需要加密的內容    [self save:localSaveKey data:[self toDictionary]];        return YES;}+ (id)localUserInfo {        id ret = nil;    NSMutableDictionary *keychainQuery = [[self class] getKeychainQuery:localSaveKey];        //__bridge_transfer是個C語言的寫法    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];        [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];        CFDataRef keyData = NULL;        if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {        //這里防止崩潰加一個try catch,因為這里不會出現野指針,故這里是用try catch能發揮作用的        @try {            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];        } @catch (NSException *exception) {            NSLog(@"Unarchive of %@ failed: %@", localSaveKey, exception);        } @finally {                    }    }        if (ret) {        return [self toModelWithDictionary:ret];    }    return ret;}#pragma mark - private- (void)save:(NSString *)saveKey data:(id)data {        NSMutableDictionary *keychainQuery = [[self class] getKeychainQuery:saveKey];        SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);    CFRelease((__bridge CFTypeRef)(keychainQuery));        [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData] ;        SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);    CFRelease((__bridge CFTypeRef)(keychainQuery));}+ (void)deleteUserInfo {    NSMutableDictionary *keychainQuery = [[self class] getKeychainQuery:localSaveKey];    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);    CFRelease((__bridge CFTypeRef)(keychainQuery));}+ (NSMutableDictionary *)getKeychainQuery:(NSString *)saveKey {    return [NSMutableDictionary dictionaryWithObjectsAndKeys:            (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,            saveKey, (__bridge_transfer id)kSecAttrService,            saveKey, (__bridge_transfer id)kSecAttrAccount,            (__bridge_transfer id)kSecAttraccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,            nil];}#pragma mark - rewrite super class- (BOOL)isEqual:(id)object {    //對比是否相同    if (![object isKindOfClass:[self class]]) {        return  NO;    }        NSDictionary *selfDict = [self toDictionary];    NSDictionary *objectDict = [(QYJUserInfo *)object toDictionary];    return [selfDict isEqualToDictionary:objectDict];}- (NSComparisonResult)compare:(QYJUserInfo *)otherObject {    //根據自己的需要是添加對比的條件    return [self.cname compare:otherObject.cname];}@end

      現在來試試效果,我們在AppDelegate.m里面去構建一個對象,我們采用字典去生成一個,打印出相對應的數據并且保存起來。
#import "AppDelegate.h"#import "QYJUserInfo.h"@interface AppDelegate ()@end@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {        NSDictionary *userInfoDict = @{                           @"username"  :     @"123456789",                           @"password"  :     @"*******",                           @"email"     :     @"xxxxx@163.com",                           @"deleted"   :     @"0",                           @"id"        :     @"666",                           @"cname"     :     @"狗剩",                           @"phone"     :     @"182xxxx3233",                           @"type"      :     @"M",                           @"ename"     :     @"Tom",                           @"created_dt":     @"2011-02-03",                           @"updated_dt":     @"2017-02-08"                           };    QYJUserInfo *object = [QYJUserInfo toModelWithDictionary:userInfoDict];        NSLog(@"%@", object);        [object saveObjectToLocal];        return YES;}為了方便我們的打印,我們去QYJUserInfo.m中去重寫一下- (NSString *)description。
- (NSString *)description {    NSArray *propertyNames = [[self class] getPropertyNames];    NSString *result = nil;    for (NSString *propertyName in propertyNames) {        NSString *temp =  [NSString stringWithFormat:@"%@:%@/n", propertyName, [self valueForKey:propertyName]];        if (!result) {            result = temp;        } else {            result = [result stringByAppendingString:temp];        }    }    return result;}

運行結果:

修改AppDelegate的代碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {        QYJUserInfo *object1 = [QYJUserInfo localUserInfo];        NSLog(@"delete before : %@", object1);        //刪除本地的檔案    [QYJUserInfo deleteUserInfo];        //在獲取一次本地的檔案,查看是否可以獲取    QYJUserInfo *object2 = [QYJUserInfo localUserInfo];        NSLog(@"delete after : %@", object2);        return YES;} 運行結果:

         用戶數據存儲就完成了。

2.如何創建一個數據庫

        首先,我們要知道,GYDataCenter(下面簡稱GY)這個框架創建表的時候,不需要我們去寫創建語句,也不用像FMDB那樣,每次增刪查改的時候都要讀取數據。只要調用相關的該表的SQL語句,框架內部就可以自動創建。

GYDataCenter的github地址:https://github.com/Zepo/GYDataCenter

開始創建一個本地的數據庫,建庫的方法有很多,可以用一些數據庫工具創建一個空的數據庫,放到工程里面,也可以用代碼去創建。這里通過講解一個簡單的場景去學習如何使用數據庫。

我們要做的事情很簡單,就是讀取手機通訊錄的數據,然后轉化成相應的數據保存到我們的數據庫中,這里我們先寫一個通訊錄的表。GYDataCenter只是一層封裝,不包括FMDB,這里我們要從github上面把FMDB下載下來,導入到工程里面,同時依賴需要的靜態庫——libsqlite3.0.tbd。編譯,無報錯,GYDataCenter和FMDB就可以使用了。

創建一個繼承于GYModelObject這類的通訊錄類,繼承GYModelObject之后就可以使用GY的一下數據庫的相關方法。

#import "GYModelObject.h"@interface QYJContactsInfo : GYModelObject/** *  主鍵 */@property (assign, nonatomic, readonly) NSInteger primaryKeyId;/** *  聯系人姓名 */@property (strong, nonatomic, readonly) NSString *name;/** *  顧客姓名首字母 */@property (strong, nonatomic, readonly) NSString *nameFirstLetter;/** *  顧客姓名拼音 */@property (strong, nonatomic, readonly) NSString *namePinyin;/** *  電話號碼 */@property (strong, nonatomic, readonly) NSString *phoneNum;- (NSDictionary *)toDictionary;@end .m文件

#import "QYJContactsInfo.h"#import <objc/runtime.h>#define PrimaryKeyId  @"primaryKeyId"@implementation QYJContactsInfo+ (NSString *)dbName {    //需要將表存放的數據庫    return @"thisIsDatabaseName";}+ (NSString *)tableName {    //數據存放的表名字    return @"thisIsTableName";}+ (NSString *)primaryKey {    //主鍵的字段名    return PrimaryKeyId;}+ (NSArray *)persistentProperties {    //這里是返回你的屬性名,順序和@interface中聲明的是一樣的    static dispatch_once_t onceToken;    static NSArray *properties = nil;    dispatch_once(&onceToken, ^{        properties = @[                       @"primaryKeyId",                       @"name",                       @"nameFirstLetter",                       @"namePinyin",                       @"phoneNum",                       ];    });        return properties;}- (BOOL)isEqual:(id)object {    if (![object isKindOfClass:[self class]]) return NO;    NSDictionary *selfDict = [self toDictionary];    NSDictionary *tempDcit = [(QYJContactsInfo *)object toDictionary];        return [selfDict isEqualToDictionary:tempDcit];}- (NSString *)description {    NSArray *propertyNames = [[self class] getPropertyNames];    NSString *result = nil;    for (NSString *propertyName in propertyNames) {        NSString *temp =  [NSString stringWithFormat:@"%@:%@/n", propertyName, [self valueForKey:propertyName]];        if (!result) {            result = temp;        } else {            result = [result stringByAppendingString:temp];        }    }    return result;}- (NSDictionary *)toDictionary {    NSMutableDictionary *dict = @{}.mutableCopy;    NSArray *propertyName = [[self class] getPropertyNames];        for (NSString *property in propertyName) {        id value = [self valueForKey:property];        //這里字典不能傳入一個nil的對象,這里就加一個判斷        if ([property isEqualToString:PrimaryKeyId]) {            //自增的ID,自動填寫,無需自己手動編號,一般于業務無關,這里轉字典的時候,根據實際需求修改            continue;        }        [dict setValue:value ? value : @""  forKey:property];    }    return dict;}+ (NSArray *)getPropertyNames {    NSMutableArray *names = @[].mutableCopy;    u_int count;    objc_property_t *properties  = class_copyPropertyList(self, &count);        for (int i=0; i<count; i++) {        objc_property_t property = properties[i];                NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];                [names addObject:propertyName];            }    //釋放    free(properties);        return names;}@end

+ (NSString *)dbName;

+ (NSString *)tableName; 

+ (NSString *)primaryKey;

+ (NSArray *)persistentProperties; 

這三個方法必須實現,這里關系到數據表的創建和使用。一個數據表的創建方式大體就是這樣子了,除上述4個方法開發者根據業務的需求去增加的。

接下來就是去獲取我們通訊錄,聯系人的數據了。這里要注意一下權限的問題,在iOS 10中,通訊錄權限必須要在.plist文件里面去聲明注冊,否則在iOS10以上的機子上會出現閃出。

.plist文件里面添加

<key>NSContactsUsageDescription</key>

    <string>訪問您的通訊錄</string>

這里是注冊權限,

iOS 9以后有一個新的獲取通訊錄聯系人的API,這里不做深入探討,有興趣的可以自己查看API文檔或者去看其他大神的技術分享博客。

   //iOS 9之前

   #import <AddressBook/AddressBook.h>

   //iOS 9以后

   #import <ContactsUI/ContactsUI.h>

簡單的獲取通訊錄聯系人代碼:

#import "QYJContactsInfoManager.h"//iOS 9之前#import <AddressBook/AddressBook.h>//iOS 9以后#import <ContactsUI/ContactsUI.h>@implementation QYJContactsInfoManager+ (NSMutableArray *)addressBookiOSNineBefore {    //新建一個通訊錄類    __block ABAddressBookRef addressBooks = nil;    //addressBooks =  ABAddressBookCreateWithOptions(NULL, NULL);        if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {        ABAddressBookRequestAccessWithCompletion(addressBooks, ^(bool granted, CFErrorRef error){            CFErrorRef *error1 = NULL;            addressBooks = ABAddressBookCreateWithOptions(NULL, error1);                    });    }    else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized){        CFErrorRef *error = NULL;        addressBooks = ABAddressBookCreateWithOptions(NULL, error);    }    else {        return [[NSMutableArray alloc] init];    }            //獲取通訊錄權限    dispatch_semaphore_t sema = dispatch_semaphore_create(0);    ABAddressBookRequestAccessWithCompletion(addressBooks, ^(bool granted, CFErrorRef error){dispatch_semaphore_signal(sema);    });    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);        //獲取通訊錄中的所有人    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBooks);    //通訊錄中人數    CFIndex nPeople = ABAddressBookGetPersonCount(addressBooks);        NSMutableArray *addressBookTemp = [[NSMutableArray alloc] init];        //循環,獲取每個人的個人信息    for (NSInteger i = 0; i < nPeople; i++)    {        //獲取個人        ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);        //獲取個人名字        CFTypeRef abName = ABRecordCopyValue(person, kABPersonFirstNameProperty);        CFTypeRef abLastName = ABRecordCopyValue(person, kABPersonLastNameProperty);        //        CFTypeRef adBirthDay = ABRecordCopyValue(person, kABPersonBirthdayProperty);        CFStringRef abFullName = ABRecordCopyCompositeName(person);        NSString *nameString = (__bridge NSString *)abName;        NSString *lastNameString = (__bridge NSString *)abLastName;        //        NSString *birthDay = (__bridge NSString *)adBirthDay;        NSString *tel ;                if ((__bridge id)abFullName != nil) {            nameString = (__bridge NSString *)abFullName;        } else {            if ((__bridge id)abLastName != nil)            {                nameString = [NSString stringWithFormat:@"%@ %@", nameString, lastNameString];            }            nameString = @"";        }        ABPropertyID multiProperties[] = {            kABPersonPhoneProperty,            kABPersonEmailProperty        };        NSInteger multiPropertiesTotal = sizeof(multiProperties) / sizeof(ABPropertyID);        for (NSInteger j = 0; j < multiPropertiesTotal; j++) {            ABPropertyID property = multiProperties[j];                        ABMultiValueRef valuesRef = ABRecordCopyValue(person, property);            NSInteger valuesCount = 0;            if (valuesRef != nil) valuesCount = ABMultiValueGetCount(valuesRef);                        if (valuesCount == 0) {                CFRelease(valuesRef);                continue;            }                        for (NSInteger k = 0; k < valuesCount; k++) {                CFTypeRef value = ABMultiValueCopyValueAtIndex(valuesRef, k);                tel = (__bridge NSString*)value;                NSMutableDictionary * pinyinDic = [[NSMutableDictionary alloc]init];                if (nameString != nil && tel != nil) {                    if (nameString.length == 0) {                        nameString = tel;                    }                    [pinyinDic setObject:nameString forKey:@"name"];                    [pinyinDic setObject:tel forKey:@"phoneNum"];                } else{                    continue;                }                [addressBookTemp addObject:pinyinDic];                CFRelease(value);            }            CFRelease(valuesRef);        }            }    return addressBookTemp;}@end

在AppDelegate中調用相關的API,

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    //獲取聯系人    NSMutableArray *contacts = [QYJContactsInfoManager addressBookiOSNineBefore];    //打印路徑,方便查看    NSLog(@"%@, %@", contacts, NSHomeDirectory());        for (NSDictionary *dict in contacts) {        //用一個字典去生成對象        QYJContactsInfo *contactsInfo = [QYJContactsInfo objectWithDictionary:dict];        //保存到數據庫中        [contactsInfo save];    }        return YES;}運行結果:

調用 save方法就開始保存到數據庫里面,只要調用了數據庫,這里就會自動去生成數據庫和數據表。

如果使用真機調試可以用同步助手或者itune去查看數據庫,這里是用模擬器,使用SQLite Professional來打開數據庫。

數據庫里面的內容:

數據庫和數據表的創建就是這樣了,下一篇博客詳細的數據操作。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 子洲县| 泗水县| 长海县| 天门市| 友谊县| 潍坊市| 临邑县| 汉寿县| 手机| 汝阳县| 城固县| 广平县| 抚宁县| 水富县| 凤翔县| 辽中县| 呼伦贝尔市| 颍上县| 高雄市| 桦甸市| 新河县| 定边县| 兰溪市| 宁安市| 公主岭市| 安阳县| 行唐县| 长子县| 宜州市| 墨江| 新乐市| 安塞县| 乐山市| 睢宁县| 平武县| 福州市| 射阳县| 乌鲁木齐县| 安义县| 沧州市| 永川市|