成员变量:
定义了一个类的全局变量(不直接被外部访问,只能通过方法读或写)
属性:
提供了getter和setter方法的成员变量(直接能被外部访问)
由此而知:当在OC里面默认申明一个属性,如果没有关联相应的成员变量会默认生成一个以下划线开头+属性名的成员变量
hardworking
成员变量:
定义了一个类的全局变量(不直接被外部访问,只能通过方法读或写)
属性:
提供了getter和setter方法的成员变量(直接能被外部访问)
由此而知:当在OC里面默认申明一个属性,如果没有关联相应的成员变量会默认生成一个以下划线开头+属性名的成员变量
包含多个变量或者数组的集合
1.结构体定义
struct 结构体名{
变量或数组
};
2.结构体定义,并且初始化结构体变量 struct1
struct 结构体名{
。。。
}结构体变量名struct1;
每个实例对象有个isa的指针,指向对象的类,Class也有isa的指针,指向MeteClass(元类)可以理解为表明所属权,声明了实例与所属类的关系
class(类) pair(元类)
Object-c的一个类也是一个对象,也可以发送消息给一个类
|
|
|
|
|
|
Objective-C对象(这儿是NSCFString)在发送消息时,运行时库会追寻着对象的isa指针得到了对象所属的类(这儿是NSCFString类)。这个类包含了能应用于这个类的所有实例方法和指向超类的指针以便可以找到父类的实例方法。运行时库检查这个类和其超类的方法列表,找到一个匹配这条消息的方法(在上面的代码里,是NSString类的writeToFile:atomically:encoding:error方法)。运行时库基于那个方法调用函数(IMP)
重点就是类要定义这个你发送给对象的消息。
Objective-C的一个类也是一个对象。这意味着你可以发送消息给一个类。
总结说OC中所有的类都是一种对象。由一个类实例化来的对象叫实例对象,那么,类作为对象(称之为类对象),又是什么类的对象?就是元类(Metaclass)元类就是类对象所属的类。所以,实例对象是类的实例,类作为对象又是元类的实例。已经说了,OC中所有的类都属于一种对象,所以元类也是对象,那么元类是什么的实例呢?答曰:根元类,根元类是其自身的实例.也就是说根元类的元类就是它自己。基类的元类的isa指针指向他自己。
用一张图表明他们之间的关系:
注意:根元类的superclass不是nil而是根类。对于OC原生的类,根元类的父类就是系统的根类NSOject。但根类不一定是NSObject,因为后面介绍的objc_allocateClassPair函数也可创建出一个根类。
元类是必不可少的,因为它存储了类的类方法。每个类都必须有独一无二的元类,因为每个类都有独一无二的类方法
|
|
在这个示例里,defaultStringEncoding被发送给了NSString类。
因为Objective-C中每个类本身也是一个对象。如上面所展示的,这意味着类结构必须以一个isa指针开始,从而可以和objc_object在二进制层面兼容,然后这个结构的下一字段必须是一个指向超类的指针(对于基类则为nil)。
实例对象:当我们在代码中new一个实例对象时,拷贝了实例所属的类的成员变量,但不拷贝类定义的方法。调用实例方法时,根据实例的isa指针去寻找方法对应的函数指针。
类对象:是一个功能完整的对象。特殊之处在于它们是由程序员定义而在运行时由编译器创建的,它没有自己的实例变量(这里区别于类的成员变量,他们是属于实例对象的,而不是属于类对象的,类方法是属于类对象自己的),但类对象中存着成员变量与实例方法列表。
元类对象:OC 的类方法是使用元类的根本原因,因为其中存储着对应的类对象调用的方法即类方法。其他时候都倾向于隐藏元类,因此真实世界没有人发送消息给元类对象。元类的定义和创建看起来都是编译器自动完成的,无需人为干涉。要获取一个类的元类,可使用如下定义的函数:
|
|
此外还有一个获取对象所属的类的函数:
由于类对象是元类的实例,所以当传入的参数为类名时,返回的就是指向该类所属的元类的指针。
runtime是一套比较底层的C语言API,属于一个C语言库,包含了很多底层的C语言API
平时编写的OC代码,在程序运行过程中,其实都是转成了runtime的C语言代码,runtime算是OC的幕后工作者
头文件:
12 <objc/runtime.h><objc/message.h>
- 可以动态地创建类
- 动态的添加变量和属性,动态地遍历变量和属性
- 动态地添加方法,转化方法
比如公司项目后期突然提出新的需求要为所有页面添加统计功能,也就是用户进入这个页面就统计一次,
实现:给UIViewController写一个类别加到pch
类别中新建一个swillingViewDidLoad方法
在实现中,+(load)中运用runtime的method_exchangeImplementations替换掉系统的viewDidload方法和swillingViewDidLoad方法;
在swillingViewDidLoad方法中加入统计方法,然后调用swillingViewDidLoad方法
这样,当controller调用viewDidload时通过运行时,指向了自定义的swillingViewDidLoad,在这个方法里先执行了我们的统计方法,然后调用swillingViewDidload方法,指向系统的viewDidload方法,这样就实现了在每个类viewDidload前进行统计的操作。
还有数组越界,给系统的NSArray 替换一个自定义objectAtIndex
分类里面不能添加Ivar是因为分类本身并不是一个真正的类,它并没有自己的ISA。有兴趣可以研究一下类是怎么被创建出来的,类最开始生成了很多基本属性,比如IvarList,MethodList,分类只会将自己的method attach到主类,并不会影响到主类的IvarList。这就是为什么分类里面不能增加成员变量的原因。
runtime中的category
所有的关联对象都由AssociationsManager管理,而AssociationsManager定义如下:
|
|
AssociationsManager里面是由一个静态AssociationsHashMap来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局map里面。而map的的key是这个对象的指针地址(任意两个不同对象的指针地址一定是不同的),而这个map的value又是另外一个AssociationsHashMap,里面保存了关联对象的kv对。
|
|
runtime的销毁对象函数objc_destructInstance里面会判断这个对象有没有关联对象,如果有,会调用_object_remove_assocations做关联对象的清理工作。
归档和解档,利用runtime遍历模型对象的所有属性,写成宏文件
利用runtime遍历模型对象的所有属性,根据属性名从字典中取出对应的值,设置到模型的属性上
利用runtime动态产生一个类
当我们像一个对象发送消息[Receiver message],Receiver没有实现该消息,即[Receiver respondsToSelector:SEL]返回为NO情况下,其实系统不会立刻出现crash,这时Runtime system会对message进行转发。转发之后,如果该消息依然没有被执行就会出现Crash!Runtime System为我们提供了三种解决这种给对象发送没有实现消息方案。
相关函数
strong 与 copy 区别:
使用strong,指向同一个地址,并且引用计数加1;而使用copy,是内容复制,创建一个新的内存区域
深拷贝与浅拷贝:
https://www.mikeash.com/pyblog/friday-qa-2012-11-09-dyld-dynamic-linking-on-os-x.html
the OS X dynamic linker
static linking, generally referred to simply as ‘linking’. This is the step that typically happens after compiling, where the machine language the compiler churned out from your source code, the object files, are ‘linked’ together into a single binary file
LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能
The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
LLVM架构的主要组成部分:
前端:前端用来获取源代码然后将它转变为某种中间表示,我们可以选择不同的编译器来作为LLVM的前端,如gcc,clang。
Pass(通常翻译为“流程”):Pass用来将程序的中间表示之间相互变换。一般情况下,Pass可以用来优化代码,这部分通常是我们关注的部分。
后端:后端用来生成实际的机器码。
实现下如何在iOS端的网页中自动顺序播放多首歌曲:由于iOS端Safari安全机制的限制,iOS端中的web不能autoplay。
window.addEventListener('touchstart', forceSafariPlayAudio, false)
监听手势触发,做“伪”自动播放。
audioEl.addEventListener('ended', function(){},false)
方法监听歌曲播放结束时的状态,用七牛云存储获得音乐src,顺序播放三个曲目。
|
|
|
|
|
|
正则表达式是个神奇的东西,这种东东就该备着以防不时之需,哈哈。
判断手机号的正则表达式
|
|
使用
|
|
单例,作为日常中出场率较高的设计模式,还是值得单独一篇文章来列举下常见的创建方式,Objective-C 下,一般是这么创建单例。
|
|
在使用单例时我们需要知道:
单例是全局唯一,在程序的生命周期中不管在何处使用都应该是同一个对象。
确保单例的唯一性,需要是初始化方法私有化,需要我们重载类的所有初始化方法。
也因为第一条,在生命周期中只有唯一一个,我们需要确保单例的线程安全。
|
|