单例模式
单例简介
-
单例是生命周期与程序生命周期相同,仅能生成一次、且不能被销毁的唯一实例;
-
需要确保应用中的一个特定类有且仅有一个实例(对象);
-
单例可在程序任何位置被访问,且一直存在;
-
单例实例获取方法命名规则:一般以standard…、shared…、default….开头;
-
单例必须至少满足以下条件:
-
只初始化一次;
-
全局存在;
-
唯一,对象不可改;
-
方便获取,任何位置可访问
-
系统单例
-
UIApplication:应用程序单例
-
NSNotificationCenter:通知中心单例
-
NSUserDefaults:用户默认单例
-
NSFileManager:文件管理单例
单例优点
-
共享信息;
-
实例控制:Singleton会阻止其他对象实例化其自己的Singleton对象的副本,从而确保所有对象都访问唯一实例;
-
灵活性:因为类控制了实例化过程,所以类可以更加灵活地修改实例化过程;
自定义单例创建常用方法
首先创建一个继承于NSObject的类Singleton,其次在Singleton.m文件中实现如下代码;
- 方法1:一般创建
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"Singleton.h"</span></span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 静态变量保证单例对象始终存在</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Singleton *singleton = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@implementation</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Singleton</span></span> + (instancetype)defaultSingleton { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 仅在单例对象为空时初始化一次,之后直接返回唯一的单例对象</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (singleton == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>) { singleton = [[Singleton alloc] init]; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> singleton; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@end</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>
- 方法2:GCD创建(推荐使用)
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"Singleton.h"</span></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Singleton *singleton = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@implementation</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Singleton</span></span> + (instancetype)defaultSingleton { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">dispatch_once_t</span> onceToken; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">dispatch_once</span>(&onceToken, ^{ singleton = [[Singleton alloc] init]; }); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> singleton; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@end</span> </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
自定义单例创建完整方法
-
一般创建单例方法可能会出现一些问题,我们通过不同的途径得到不同的对象,显然是不行的。我们必须要确保对象的唯一性,所以我们就需要封锁用户通过alloc/init/copy以及release/retain等方法来构造或操作对象这条道路。
-
我们知道,创建对象的步骤分为申请内存(alloc)、初始化(init)这两个步骤,我们要确保对象的唯一性,因此在第一步这个阶段我们就要拦截它。当我们调用alloc方法时,oc内部会调用allocWithZone这个方法来申请内存,我们覆写这个方法,然后在这个方法中调用defaultSingleton方法返回单例对象,这样就可以达到我们的目的。拷贝对象也是同样的原理,覆写copyWithZone方法,注意需遵守
<NSCopying>
协议,然后在这个方法中调用defaultSingleton方法返回单例对象,其他示例直接参考如下代码:
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Singleton *singleton = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; + (instancetype)defaultSingleton { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!singleton) { singleton = [[Singleton alloc] init]; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> singleton; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// alloc</span> + (instancetype)allocWithZone:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> _NSZone *)zone { @synchronized(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!singleton) { singleton = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> allocWithZone:zone]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> singleton; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// copy</span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)copyWithZone:(NSZone *)zone { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// retain</span> - (instancetype)retain { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// release</span> - (oneway <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)release { } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// autorelease</span> - (instancetype)autorelease { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// retainCount</span> - (NSUInteger)retainCount { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> NSUIntegerMax; } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li></ul>
单例使用
首先在main.m文件中,引入“Singleton.h”,其次创建两个单例实例,并且打印对象信息;
我们可以看到,两个实例对象的地址是一致的,由此可见,单例的唯一性。
可利用单例的唯一性进行传值,但必须满足一个前提条件就是,在传值时,必须保证单例存在并且单例属性确实有值。
现在在Singleton.h文件中声明属性name,其次创建一个Person类,为其设置属性name,并且重写init方法,通过单例对name直接复制,如下所示:
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"Person.h"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"Singleton.h"</span></span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@implementation</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Person</span></span> - (instancetype)init { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> init]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 获取单例属性值赋给name</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.name</span> = [Singleton defaultSingleton]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.name</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@end</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
切换到main.m文件中,创建单例实例,并且给name属性复制,其次实例化Person对象,并打印person.name,如下所示:
<code class="hljs vala has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <Foundation/Foundation.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import "Singleton.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import "Person.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> * argv[]) { @autoreleasepool { <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma mark - 单例模式</span> Singleton *singleton = [Singleton defaultSingleton]; singleton.name = @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Admin"</span>; Person *person = [[Person alloc] init]; NSLog(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Person's name is '%@'."</span>, person.name); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Person's name is 'Admin'.</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
从上述代码中可以看出,可通过单例进行传值操作。
KVC 键值编码
概述
-
KVC是KeyValueCoding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性(实例变量)的机制。而不是通过调用Setter、Getter方法访问。通常我们使用
valueForKey
来替代getter()
方法,setValue:forKey
来代替setter()
方法。 -
当使用KVO、Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。
常用方法
- 取值方法
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、</span> valueForKey:,传入<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span>属性的名字。 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、</span> valueForKeyPath:,传入<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span>属性的路径,xx<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.xx</span>形式。</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
- 设值方法
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、</span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)setValue:(nullable <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)value forKey:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *)key; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、</span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)setValue:(nullable <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)value forKeyPath:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *)keyPath; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3、- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 4、</span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)setValue:(nullable <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)value forUndefinedKey:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *)key;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
KVC 读取方式
KVC使用起来比较简单,但是它如何查找一个属性进行读取呢?具体查找规则(假设现在要利用KVC对name进行读取):
-
如果是动态设置属性,则优先考虑调用setName方法,如果没有该方法则优先考虑搜索成员变量_name,如果仍然不存在则搜索成员变量name,如果最后仍然没搜索到则会调用这个类的setValue:forUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确设置);
-
如果是动态读取属性,则优先考虑调用name方法(属性name的getter方法),如果没有搜索到则会优先搜索成员变量_name,如果仍然不存在则搜索成员变量name,如果最后仍然没搜索到则会调用这个类的valueforUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确读取);
案例
1、声明 KVCClass
类,并在其.h文件中声明几个全局变量,无需定义成属性及生成存(setter)取(getter)方法,代码如下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">#<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> <Foundation/Foundation.h> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@interface</span> KVCClass : NSObject { NSString *_name; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**< 姓名 */</span> NSString *_nationality; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**< 国籍 */</span> NSInteger _age; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**< 年龄 */</span> } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@end</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
2、在 “KVCClass.m”文件中,重写description
方法与dealloc
方法,代码如下:
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"KVCClass.h"</span></span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@implementation</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">KVCClass</span></span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)dealloc { [_name release]; _name = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; [_nationality release]; _nationality = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> dealloc]; } - (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *)description { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> stringWithFormat:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<%p name:%@, age:%ld, address:%@>"</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>, _name, _age, _nationality]; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@end</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
3、在main.m文件中,导入KVCClass.h
,实例化对象,并通过KVC为其设值,代码如下:
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;"><Foundation/Foundation.h></span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"KVCClass.h"</span></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> * argv[]) { @autoreleasepool { <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma mark - KVC </span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、逐一赋值</span> KVCClass *kvcObject1 = [[KVCClass alloc] init]; [kvcObject1 setValue:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Charles"</span> forKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>]; [kvcObject1 setValue:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"China"</span> forKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"nationality"</span>]; [kvcObject1 setValue:@<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">22</span> forKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>]; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@"</span>, kvcObject1); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 取值</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Name is '%@'."</span>, [kvcObject1 valueForKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>]); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、统一赋值</span> KVCClass *kvcObject2 = [[KVCClass alloc] init]; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSDictionary</span> *dic = @{@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"William"</span>, @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"nationality"</span>:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"USA"</span>, @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>:@<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>}; [kvcObject2 setValuesForKeysWithDictionary:dic]; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@"</span>, kvcObject2); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 取值</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Name is '%@'."</span>, [kvcObject2 valueForKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>]); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul>
控制台输出情况如下:
Tips
1、key的值必须正确,如果拼写错误,会出现异常;
2、当key的值是没有定义的,valueForUndefinedKey:这个方法会被调用,如果你自己写了这个方法,key的值出错就会调用到这里来;
3、因为类key反复嵌套,所以有个keyPath的概念,keyPath就是用.号来把一个一个key链接起来,这样就可以根据这个路径访问下去;
4、NSArray/NSSet等都支持KVC;
KVO 键值监听
概述
-
KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。
-
在面对对象编程时,我们很多情况下直接处理某些事件会很麻烦。如常见的程序运行中电话呼入、用户突然点击home键等等,一般我们使用观察者(代理)来处理类似事件。
-
在使用这些模式的时候,我们需要告诉这些角色,谁来响应这些事件,这就需要使用类的引用。
-
类的引用本质上就是如何让另外一个角色,“知道”另外一个角色,对应到代码中,就是如何让某一个类的对象,顺利的把信息传递给另外一个对象。
-
处理类的引用的时候,应注意以下几点:
-
每个类是否能正常接收到信息(响应动作)
-
信息传递时接收者是否存在
-
每个类是否能正常释放(不会引起循环引用)
-
键值观察
-
键值观察是基于键值编码的一种技术;
-
利用键值观察可以注册成为一个对象的观察者,在该对象的某个属性变化时收到通知;
-
被观察对象需要编写复合KVC标准的存取方法;
常用方法
系统框架已经支持KVO,所以程序员在使用的时候非常简单。
1、注册指定Key路径的监听器:addObserver: forKeyPath: options: context:
2、实现回调方法: observeValueForKeyPath: ofObject: change: context:
3、删除指定Key路径的监听器:removeObserver: forKeyPath、removeObserver: forKeyPath: context:
案例
此案例将KVC与KVO结合使用
1、声明 KVOClass
类,并在其.h文件中声明全局变量_weather
;
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">#<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> <Foundation/Foundation.h> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@interface</span> KVOClass : NSObject { NSString *_weather; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**< 天气 */</span> } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@end</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
2、在“person.m”文件中实现如下代码:
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <span class="hljs-title" style="box-sizing: border-box;">"KVOClass.h"</span></span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@implementation</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">KVOClass</span></span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)dealloc { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 移除监听</span> [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> removeObserver:<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> forKeyPath:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"weather"</span>]; [_weather release]; _weather = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>; [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> dealloc]; } - (instancetype)init { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> init]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 注册监听</span> [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> addObserver:<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> forKeyPath:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"weather"</span> options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>]; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 实现监听回调方法</span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)observeValueForKeyPath:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *)keyPath ofObject:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)object change:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSDictionary</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>> *)change context:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *)context { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"天气发生变化,此时天气情况:%@"</span>, change[@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"new"</span>]); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@end</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul>
3、在“main.m”文件中导入KVOClass.h
文件,实现如下代码,观察控制台:
<code class="hljs vala has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import <Foundation/Foundation.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#import "KVOClass.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> * argv[]) { @autoreleasepool { <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma mark - KVO</span> KVOClass *kvoObject = [[KVOClass alloc] init]; [kvoObject setValue:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"晴"</span> forKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"weather"</span>]; [kvoObject release]; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
控制台输出:
<code class="hljs css has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-11-17</span> 23<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:02</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:00</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.860</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">DesignPatterns</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[1392:132353]</span> 天气发生变化,此时天气情况:晴</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
Tips
使用KVC可以大大地减少我们的代码量,当遇到property的时候,可以多想想是否可以KVC来帮助我,是否可以用KVC来重构代码, 当需要加入observer模式时,可以考虑下KVO, 在高性能的observer里面,KVO会给我们很好的帮助。
数据持久化
-
iOS应用程序使用沙盒机制作为文件存储方式;
-
应用程序有一个独立的沙盒文件夹,程序仅能访问自己沙盒路径下的文件,任何情况下都无法访问其它程序的沙盒;
-
那我们可以通过什么方法将数据存入沙盒,同时也可以取出?可同 NSUserdefaults 或 属性列表实现。
-
数据持久化的方法还有很多,如本地数据库(CoreData、sqlite、归档)、网络数据库(服务器)等等,会在后面的博客中介绍。
NSUserdefaults
常用方法
1、存值
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、获取系统单例</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSUserDefaults</span> *defaults = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSUserDefaults</span> standardUserDefaults]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、设值</span> [defaults setObject:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"William"</span> forKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3、同步数据</span> [defaults synchronize]; </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
2、取值
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、获取系统单例</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSUserDefaults</span> *defaults = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSUserDefaults</span> standardUserDefaults]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、取值</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *name = [defaults objectForKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3、打印信息</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Name is '%@'."</span>, name); </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
3、移除值
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、获取系统单例</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSUserDefaults</span> *defaults = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSUserDefaults</span> standardUserDefaults]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、删除值</span> [defaults removeObjectForKey:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3、同步数据</span> [defaults synchronize];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
Tips
1、从上述示例中可以看出,无论是什么操作,都需获取userdefaults单例,如果是存值或删除值,一定记得调用
synchronize
方法,同步数据。2、通过userdefaults同样可以进行值的传递,因为userdefaults本质也是单例。
读写文件
我们可以自己通过代码,根据一条路径自动在桌面上创建一个文件,来存取我们的数据,注意:这个数据并非存在沙河中。
获取桌面文件路径方式:直接将桌面文件拖入Xcode工程即可,Xcode会自动获取文件路径。
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSDictionary</span> *dict = @{@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"account"</span>:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Admin"</span>, @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"password"</span>:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"123456"</span>}; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1、写入文件</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将 dict 存入文件,/infomation.text 为自己给存储对象文件的命名</span> [dict writeToFile:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/Users/LiHongyao/Desktop/Datas/infomation.text"</span> atomically:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>]; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2、读取文件</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSDictionary</span> *infomation = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSDictionary</span> dictionaryWithContentsOfFile:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/Users/LiHongyao/Desktop/Datas/infomation.text"</span>]; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@"</span>, infomation);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
输出情况:
<code class="hljs delphi has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2015</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">11</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">23</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">49</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">39.302</span> DesignPatterns[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1562</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">170884</span>] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">{ account = Admin; password = 123456; }</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Program</span> ended <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">exit</span> code: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span></code>