zoukankan      html  css  js  c++  java
  • iOS开发技术分享(1)— iOS本地数据存储

    iOS开发技术分享(1)— iOS本地数据存储

    前言:

      我本是一名asp.net程序员,后来加入了iOS游戏开发队伍,到现在也有一年多的时间了。这一年来,每天都干到2、3点钟才睡觉,不为别的,只为了学多点东西。这段时间,什么都学,从C#到Objective-C,到C++,慢慢理解了编程真的不论语言,只要熟悉一种语言,想要上手另一门语言,真的是一件很简单的事情,用心者半个月即可上手工作(当然这里说的是可以上手,想要精通肯定是需要一定时间钻研的)。我想说的是,只要你喜欢,程序员真的不是一份很苦逼的工作,反之,我倒是觉得其乐融融,加油吧,程序员朋友们!

      工作之余,忙活了一个多月,终于把【美女那些图】做完了,接下来我会陆续写一些技术分享文章,包括服务端和客户端,都分享一下这个项目的核心代码。说得不对的地方,请多多包涵,并帮忙指正,谢谢。

       首先先把项目的截图贴出来,好让大家了解这个App是做什么的,本app已经适配了3.5inch和4.0inch的屏幕,如果用像素表示,则是适配了320*480、640*960以及640*1136。这里贴出在iPhone5上的截图。

    美女那些图   美女那些图   美女那些图  

    美女欣赏,绝不包含黄色内容,请放心下载。

    这里是下载地址:http://itunes.apple.com/cn/app/id590438908

    还请各位朋友捧捧场,给个好评,多谢了。

    iOS本地数据存储:

      关于iOS本地数据存储方面,常用的方法有好几种,比如plist,xml,NSUserDefaults,keychain等,但是,各自都有各自的特点,下面我就简单的把NSUserDefaults和keychain介绍一下,并给出demo,好让新手快速入门。

    1、NSUserDefaults

      一般情况下,由于NSUserDefaults存储的数据不够安全,用户可以随意根据自己的需要更改里面的数据,所以NSUserDefaults一般只会被用来存储App的设置数据等,这就好比web中的cookie,同样可以存储数据,但是不够安全。

      上代码

      Setting.h:

    复制代码
     1 #import <Foundation/Foundation.h>
     2 
     3 typedef  enum {
     4     ST_Music = 100,
     5     ST_Volume,
     6     ST_Push,
     7     ST_Num
     8 }SettingType;//各种设置的枚举
     9 
    10 @interface Setting : NSObject
    11 //读取getter
    12 + (bool)getIsEnableByType:(SettingType)type;
    13 //设置setter
    14 + (void)setIsEnable:(bool)isEnable byType:(SettingType)type;
    15 //清空数据
    16 + (void)resetData;
    17 
    18 @end
    复制代码

      setting.mm

    复制代码
     1 #import "Setting.h"
     2 
     3 #define KEY_SETTING       @"BeautyPics_"
     4 
     5 @implementation Setting
     6 
     7 + (void)resetData
     8 {
     9     for (SettingType type = ST_Music; type < ST_Num; type++) {
    10         [Setting setIsEnable:true byType: type];//默认全部为true
    11     }
    12 }
    13 
    14 + (bool)getIsEnableByType:(SettingType)type
    15 {
    16     NSString * key = [KEY_SETTING stringByAppendingFormat:@"%d", type];
    17     id isEnable = [[NSUserDefaults standardUserDefaults] objectForKey: key];
    18     if (isEnable == nil) {
    19         [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool: true] forKey:key];
    20         [[NSUserDefaults standardUserDefaults] synchronize];
    21         return true;
    22     }
    23     return [isEnable boolValue];
    24 }
    25 
    26 + (void)setIsEnable:(bool)isEnable byType:(SettingType)type
    27 {
    28     NSString * key = [KEY_SETTING stringByAppendingFormat:@"%d", type];
    29  
    30     if ([Setting getIsEnableByType: type] != isEnable) {
    31         [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool: isEnable] forKey:key];
    32         [[NSUserDefaults standardUserDefaults]synchronize];
    33     }
    34 }
    35 
    36 @end
    复制代码

      以上代码一目了然,需要注意的是,每次设置完数据之后,一定要通过 [[NSUserDefaults standardUserDefaults] synchronize]来同步,否则数据将不会保存起来。

     

    2、keychain

      既然NSUserDefaults不够安全,那么有没有一些比较安全的本地数据存储方式呢,答案当然是有的,这就是keychain,keychain只能该App本身访问,其他的App不能访问(当然现在只要通过设置是可以的。但是要通过这种形式:App1同意App2访问,App2才能访问到App1所存储的keychain)。关于keychain的文章很多,我不重复其原理,这里举出其用法,keychain的存储方式同样也是字典,也就是NSMutableDictionary,下面上代码:

      (1)保存数据。其中data可以是NSArray、NSSet,NSDictionary等,一般情况下这三种数据结构已经足够用了。service就是要存储的key了。

    复制代码
    + (void)saveData:(NSString *)service data:(id)data
    {
        //Get search dictionary
        NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
        //Delete old item before add new item
        SecItemDelete((CFDictionaryRef)keychainQuery);
        //Add new object to search dictionary(Attention:the data format)
        [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
        //Add item to keychain with the search dictionary
        SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
    }
    复制代码

      (2)读取数据。直接通过保存数据是使用的key即可读取所存数据。

    复制代码
    + (id)loadData:(NSString *)service
    {
        id ret = nil;
        NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
        //Configure the search setting
        //Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue
        [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
        [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
        CFDataRef keyData = NULL;
        if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
            @try {
                ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData];
            } @catch (NSException *e) {
                NSLog(@"Unarchive of %@ failed: %@", service, e);
            } @finally {
            }
        }
        if (keyData)
            CFRelease(keyData);
        return ret;
    }
    
    + (NSMutableDictionary *)getKeychainQuery:(NSString *)service
    {
        NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                      (id)kSecClassGenericPassword,(id)kSecClass,
                                      service, (id)kSecAttrService,
                                      service, (id)kSecAttrAccount,
                                      (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
                                      nil];
        return dict;
    }
    复制代码

      

      (2)demo。以上已经可以实现使用keychain读取和存储数据了。那么接下来我们来一小段demo。

    比如我要存储NSDictionary,用户名为“阿泰”,密码为“123456”,则:

    1 NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:@"阿泰",@"key_username",@"123456",@"key_pwd", nil];
    2  [Keychain saveData:KEY_USER_DATA_ALL data: dict];

      其中 KEY_USER_DATA_ALL 为所保存的数据的key,可以通过这个key把保存的字典读出来。

      读取时,如下:

    1 NSDictionary * loadDict = [Keychain loadData: KEY_USER_DATA_ALL];

      如此就把刚刚存储的字典dict读出来了,接下来要做的事情当然变得随心所欲。

         这里是下载地址:http://itunes.apple.com/cn/app/id590438908

       二维码下载:

      未完待续。。。下一篇文章,将讲到开源类库 ASIHttpRequest 和 SDWebImage 的使用。

  • 相关阅读:
    C++ 内置宏定义 与 预编译指令
    C++ 反射机制的简单实现
    Intellij打包jar文件,“java.lang.SecurityException: Invalid signature file digest for Manifest main attrib
    IntelliJ IDEA 运行你的第一个Java应用程序 idea运行main方法
    IDEA重新打jar包时报错MANIFEST.MF already exists in VFS
    在 RPA10.X 运行异常,RPA9 却正常的问题处理
    Python判断文件是否存在的三种方法
    Python日期时间函数
    Chrome提示:"请停用以开发者模式运行的扩展程序"的解决办法
    Win10提示“无法打开此计算机上的组策略对象”如何解决
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3312653.html
Copyright © 2011-2022 走看看