iOS应用开发基础(四)基础知识(数据存储和多线程)

本文可能涉及很多零碎的知识点,其中包括iOS应用开发的相关基础知识。以后会针对每个条目在进行深入研究,这里只是先做一个相关知识的概述总结。

iOS的数据存储

大多数iOS程序其功能总结为:提供一套界面,帮助用户管理特定数据。在这个过程中,不同对象各司其职:模型对象负责保存数据,视图对象负责显示数据,控制器对象负责在模型对象与视图对象之间同步数据。

固化和解固

由iOS SDK提供的一种保存和读取对象的机制。固化某个对象的时候,会将其所有属性存入指定的文件中。解固某个对象时,会从指定的文件读取相应的数据,然后根据数据还原对象。

为了固化和解固某个对象,必须要遵守NSCoding协议,并且实现两个必需方法:encodeWithCoder方法:和initWithCoder:方法。

-(void)encodeWithCoder:(NSCode *)aCoder{
    [aCoder encodeObject:self.itemName forKey:@"itemName"];
}
-(instancetype) initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    if(self){
            _itermName = [aDecoderdecodeObjectForKey:@"itemName"];
    }
}

存放路径

iOS应用可以在运行时载入应用程序包中的文件。要获得应用程序包中的某个文件的全路径,需要首先得到代表应用程序包的NSBundle对象,然后通过该对象得到某个文件的全路径,代码如下:

NSBundle *applicationBundle = [NSBundle mainBundle];
NSString *path = [applicationBundle pathForResource:@"myImage" ofType:@"png"];

如果应用程序需要保存程序参数、选项相关的少量数据,则可以使用NSUserDefaults进行保存;如果应用程序只有少量数据需要保存,那么使用属性列表就可以了;如果应用程序有大量数据进行存储、访问,就需要借助于数据库了。iOS内置SQLite数据库是一个真正轻量级的数据库,他没有后台程序,整个数据库对应一个文件。并有两套API:基于c语言风格的libsqlite3.dylib和面向对象的Core Data。

应用程序沙盒目录

 1. Document:除了基于NSUserDefaults的首选项设置之外,应用程序的数据、文件都保存在该目录下
 2. Library:基于NSUserDefaults的首选项参数保存在Library/Preference目录下。
 3. Library/Caches:存放运行时生成的保留数据。iTunes或者iClound不会同步该数据。
 4. Library/Preferences: 存放所有偏好数据。可以使用NSUserDefaults类
 5. tmp:该目录提供应用程序存储的历史文件,当iOS执行同步的时候,iTunes不会备份tmp目录下的文件。
 因此当应用程序不在需要某个临时文件时,应该负责删除tmp目录下的临时文件,避免占用系统空间。运行时的临时文件。

保存、读取数据

前面介绍了固化的存放路径,下面要讲的是:1.如何保存、读取数据;2.何时保存、读取数据

保存

通过 NSKeyedArchiver类保存对象发送archiveRootObject:toFile:消息

-(BOOL)saveChagne
{
    NSString *path = [self itemArchivePath];
    return [NSKeyedArchiver archiveRootObject:self.privateItems  toFile :path];
}

上面的工作原理是:

 1. archiveRootObject:toFile:会先创建一个NSKeyedArchiver对象。
 2. 然后,archiveRootObject:toFile:会向privateItems发送encodeWithCoder:消息,并传入NSKeyedArchiver对象作为第一个参数。
 3. privateItems的encodewithCoder:方法会向其包含的多个对象一次发送encodeWithCoder消息,
 并传入NSKeyedArchiver对象。这项BNRItem对象都会将其属性编码至同一个NSKeyedArchiver对象。
 4. 当所有的对象都完成编码后,NSKeyedArchiver对象就会将数据写入指定的文件中。

何时保存

一般情况是在用户按下设备的主屏幕按钮后,AppDelegate对象会收到applicationDidEnterBackground:消息之后,发送saveChange消息;

读取

主要使用NSKeyedUnarchiver类。

-(instancetype)initPrivate
{
    self = [super init];
    NSString *psth = [self itemArchivePath];
    _privateItems = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    if(!_privateItems){
        _privateItems = [[NSMutableArray alloc] init];
    }
    return self;
}

iOS多线程

iOS大致提供了如下三种多线程编程技术。

 1. NSThread实现多线程。
 2. NSOperation与NSOperationQueue实现多线程。
 3. 使用GCD(Grand Central Dispatch)实现多线程。

NSThread的一些方法

创建一个新线程对象。

- initWithTarget:selector:object:   

创建并启动新线程。

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)arg;   

上面两种方法的本质都是将target对象的selector方法转化为线程执行体,其中selector方法最多可以接受一个参数,而arg就代表创个selector方法的参数。

*currentThread 属性返回当前正在执行的线程对象。
除此之外,可以通过setName:方法为线程设置名字,也可以通过name方法返回指定线程的名字。

线程的状态:

备注:启动线程使用start方法,线程启动之后并不是立即进入运行状态,线程内启动后处于就绪状态,当系统调度线程后, 线程才会进入运行状态。
如果程序希望子线程的start后立刻执行,程序可以使用NSThread sleepForTimeInterval:0.001让当前运行的线程睡眠1毫秒。

终止子线程:

 1. 线程正常结束。
 2. 线程执行过程中出现错误。
 3. 直接调用NSThread的exit方法,来终止当前正在执行的线程。

在iOS规定中,只能在UI线程中修改UI控件的属性。所以当子线程执行“任务”完成后,如果需要通过UI控件来显示子线程中的数据,则通常会调用performSelectorOnMainThread:withObject:waitUntilDone:方法完成。

线程的同步与线程的通信

线程同步:

1.@synchronize实现同步。被@synchronize修饰的代码块可简称同步代码块。格式如下:

@synchronize(obj)
{
...
//同步代码块。obj就是同步监视器。通过是可能被并发访问的共享资源充当同步监视器。
}

Foundation框架中很多类都有可变和不可变两种版本,比如NSString, NSArray都是不可变,他们永远是线程安全的。但是NSMutableString,NSMutaleArray就是可变得,线程不安全的。

释放对同步监视器的锁定:

 1. 块执行结束;
 2. return、goto等语句结束代码块。
 3. 出现错误、异常等。但是sleep不会释放监视器。

同步锁:NSLock

先获得NSLock对象实例,然后

[lock lock]
 ......
[lock unlock];

NSCondition控制线程通信

虽然线程在系统内运行时,线程的调度具有一定的透明性,程序通常无法准确的控制线程轮换执行,但我们可以通过一些机制来保证线程协调运行,也就是处理线程之间的通信。

Foundation提供了一个NSCondition类来处理线程通信,NSCondition实现了NSLocking协议,因此也可以调用lock、unlock来实现线程同步。NSCondition可以让那些已经锁定NSCondition对象却无法继续执行的线程释放NSCondition对象,NSCondition对象也可以唤醒其他处于等待状态的线程。
主要是三个函数:

-wait:导致当前一直等待,直到其他线程调用该NSCondition的signal或者broadcaset方法来唤醒该线程。
-signal:唤醒再次NSCondition对象等待的单个线程。如果线程都在该NSCondition对象等待,则会选择性唤醒其中一个线程。
-broadcast:唤醒在此NSCondition对象等待的所有线程。

使用GCD实现多线程。

GCD的两个核心概念:

1.队列:队列负责管理开发者提交的任务
2.任务:任务就是用户提交给队列的工作单位,这些任务提交给队列底层维护的线程池执行,因此这些任务会以多线程的方式执行。

主要是两个步骤:

1.创建队列。
2.将任务提交给队列。

创建队列函数:

dispatch_queue_t dispatch_get_current_queue(void);

dispatch_queue_t dispatch_get_global_queue(long identifier, <#unsigned long flags#>)

…..其他具体的参考开发文档

NSOperation与NSOperationQueue实现多线程。

基本理论:

NSOperationQueue:代表一个FIFO的队列,它负责管理系统提交的多个NSOperation,NSOperationQueue底层维护一个线程池,会按照顺序启动线程来执行提交给该队列的NSOperation任务。

NSOperation:代表一个多线程任务。NSOperation有两个子类:1.NSInvocationOperation、NSBlockOperation。开发者会自己实现子类,也可以直接使用该子类。

步骤:

1.创建NSOperationQueue队列,病设置相关属性。
2.创建NSOperation子类对象,并将该对象提交给NSOperationQueue队列,该队列将会按照一次启动每个NSOperation任务。

你可能感兴趣的:(iOS应用开发基础)