OC小知识点总结(updating)

439 阅读24分钟

1: 类与对象

1.1 OC类方法和对象方法对比
1. 类方法可以调用类方法 
2. 类方法不能直接调用实例方法和实例变量 
3. 类方法可以通过创建对象后,访问实例方法 
4. 实例方法可以调用类方法。
1.2 类方法的好处:
不依赖于对象,执行效率更高
1.3 类方法的场合:
 当方法内部不需要使用到成员变量时,可以改为类方法
1.4 如果在类方法中调用self 会有什么问题?
1: 在实例方法中self不可以调用类方法,此时的self不是Class。
2: 在类方法中self可以调用其他类方法。
3: 在类方法中self不可以调用实例方法。
总结:类方法中的self,是class/ 实例方法中self是对象的首地址?
1.5 对象,类对象,元类,跟元类结构体的组成以及他们是如何相关联的?
 1: 对象的结构体当中存放着isa指针和成员变量,isa指针指向类对象
 2: 类对象的isa指针指向元类,元类的isa指针指向NSObject的元类
 3: 类对象和元类的结构体有isa,superClass,cache等等
1.6 类对象包含如下内容
1: isa
2: superclass指针
3: 类的属性信息@property
4: 类的对象方法信息
5: 类的协议信息
6: 类的成员变量信息
1.7 元类对象
-   1: isa指针
-   2: superclass指针
-   3: 类的类方法信息
1.8 为什么对象方法中没有保存对象结构体里面,而是保存在类对象的结构体里面?
方法是每个对象相互可以共用的,如果每个对象都存储一份方法列表太浪费内存
由于对象的isa是指向类对象的,当调用的时候, 直接去类对象中去查找就可以了,节约了很多内存空间。    
1.9 类方法存在哪里? 为什么要有元类的存在?
类方法存于元类结构体里
所有的类自身也是一个对象, 我们可以像这个对象发送消息(调用)
为了调用类方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。
这就引出了meta-class的概念,元类中保存了创建类对象以及类方法所需的所有信息。
1.10 存储对象为什么需要16字节对齐
1: 字节是内存的容量单位。cpu 读取数据是以固定'字节块'来读取的,这是一个用空间换取时间的做法,如果频繁的读取字节未对齐的数据, CPU就需要花费大量的精力去分辨你要读取多少字节降低了`cpu`的性能和读取速度。
2: 更安全 由于在一个对象中`isa`指针是占`8`个字节,如果不进行节对齐 ,对象之间就会紧挨着,容易造成访问混乱。`16`字节对齐,会预留部分空间,访问更安全
1.11 alloc, init, new
1: alloc: alloc的核心作用就是 1: 开辟内存,2: 通过isa指针与类进行关联,
2: init方法: init什么也不做,就是给开发者使用工厂设计模式提供一个接口可以
    重写init方法提供开发者更多的自由,
3: new 是对(alloc+init)进行了封装,无法在初始化的时候添加其它的需求。
1.12 alloc 方法底层调用流程
1: alloc-> 2: objc_alloc —> 3: callAlloc
在callAlloc内部分有缓存无缓存两种情况:
1: 有缓存: 
  4: _objc_rootAllocWithZone -> 5: _class_createInstanceFromZone 
  6: -> instanceSize -> 7: calloc -> 8: initInstanceIsa
2: 无缓存:
   4: callAlloc —> 5: objc_msgSend 
—> 6: alloc —> 7: _objc_rootAlloc —> 8: callAlloc 
—> 9: _objc_rootAllocWithZone —> 10: _class_createInstanceFromZone
-> 11: instanceSize -> 12: calloc -> 13: initInstanceIsa
1.13 为什么对象内部的成员变量是以8字节对⻬,系统实际分配的内存以16字节对⻬?
以空间换时间。
苹果采取16字节对⻬,是因为OC的对象中,第一位叫isa指针,它是必然存在的, 
而且isa就占了8位字节,就算对象中没有其他的属性了,也一定有一个isa,那对象就至少要占用8 位字节。
如果以8位字节对⻬的话,如果连续的两块内存都是没有属性的对象,那么它们的内存空间就会完全的挨在一起,是容易混乱的。
以16字节为一块,这就保证了CPU在读取的时候,按照块 读取就可以,效率更高,同时还不容易混乱。
1.14 对象的本质
objc_object结构体,里面存储isa指针和成员变量的值
1.15 结构体的内存对⻬方式
1:数据成员对⻬规则:结构(struct)的第一个数据成员放在offset为0的地方,以后每个数据成员存 储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始(比如int4字节,则要从4的整 数倍地址开始存储)。
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整 数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始 存储)。
3:收尾工作:结构体的总大小,也就是sizeof的结果必须是其内部最大成员的整数倍,不足的要补⻬。
1.16 cls->instanceSize()
计算对象需要的内存的大小。
1.17 calloc()`
系统实际为对象分配内存的大小。
1.18 alloc底层三个重要的方法
1: instanceSize 计算内存的大小 - 量房子
2: calloc 申请开辟内存 - 造房子
3: initInstanceIsa 指针关联对象 - 房子下写名字
1.19 对象的本质
对象的本质是结构体
1.20 id 修饰变量和返回值为什么不加 *
id 本质是一个结构体指针
typedef struct objc_object *id;
1.21 isa的本质
isa是一个指针是isa_t类型, isa_t是一个联合体位域结构, 采用这种结构是基于内存优化的考虑(二进制中的每一位均可以代表不同的信息)
isa指针占用内存的大小是8字节, 64位
当实例方法调用时, 通过对象的isa在类中获取方法的实现
当类方法调用时, 通过类的isa在元类中获取方法的实现
1.22 数组指针
  1: 数组的地址就是数组元素中的首地址,即&c和&c[0]都是首地址
  2: 数组中每个元素之间的地址间隔,根据当前元素的数据类型决定的
  3: 数组的元素地址可以通过首地址+n*类型大小方式,这种方式是数组中的元素类型必须相同。
  4: 数组元素不相同用首地址+偏移量方式,根据当前变量的偏移值(需要前面类型大小相加)

Image 2022-4-28 at 2.52 PM.jpg

1.23 NSObject的isa走位
1: NSObject的对象obj的isa --> NSObject2: NSObject类的isa --> 根元类
3: 根元类的isa --> 根元类(指向自己)
4: NSObject 的父类是nil
1.24 自定义对象(eg: A *a = [[A alloc] init])的isa走位
-   A的对象a的isa --> A类
-   A类的isa--> A类的元类
-   元类isa--> 根元类
1.25 类的本质
1: Class 在底层类型是objc_class *
2: objc_class继承objc_object
3: objc_object里面只有一个成员变量isa, isa占8字节
4: object_class 里面有三个成员变量: 
    1: Class superClass 结构体指针占8字节
    2: cache_t cache 结构体类型大小, 由内部成员变量决定 占16字节
    3: class_data_bits_t bits 
5: isa的内存地址是首地址
6: superClass的内存地址是首地址 + 0x8
7: cache的内存地址是 首地址 + 0x10
8: bits的内存地址是 首地址 + 0x20
1.26 object_class 里的bits存储了什么
1: 属性列表
2: 方法列表
3: 成员变量列表
4: 协议列表
bits.data()存储class_rw_t*类型的数据, class_rw_t是结构体类型, 方法, 属性, 成员变量, 协议都在 class_rw_t中对应方法:

Screen Shot 2022-04-28 at 5.02.58 PM.png

1.28 类方法存储在哪里
类方法存储在元类的方法列表里
1.29 id 和 instancetype的区别?
1:  id 本质是一个结构体指针 typedef struct objc_object *id;
2:  id 可以作为方法的返回以及参数类型, 也可以用来定义变量
3:  instancetype 只能作为函数或者方法的返回值
4:  instanceType 会在编译时检查实例的类型,而`id`在编译时不检查,只在运行时才会去检查实例的类型;
1.30 New 的作用是?
1.  向计算机(堆区)申请内存空间;
1.  给实例变量初始化;
1.  返回所申请空间的首地址;

2: Crash 相关

2.1 什么是野指针?
1: 野指针就是指向一个被释放或者被收回的对象,但是对指向该对象的指针没有做任何修改,以至于该指针让指向已经回收后的内存地址。
2: 其中访问野指针是没有问题的,使用野指针的时候会出现崩溃Crash
例子如下:
   __unsafe_unretained** NSView *test = [[NSView alloc] init];

      NSLog(@"test 指针指向的地址:%p 指针本身的地址:%p", test, &test);
     // 可以看到NSlog打印不会闪退,调用[test setNeedsLayout]; 会闪退
      [test setNeedsLayout];
2.2 如何检测野指针?(待整理)
https://www.jianshu.com/p/9fd4dc046046?utm_source=oschina-app
https://www.jianshu.com/p/2937105132f6

2.3 导致Crash的原因有哪些?

1、找不到方法的实现unrecognized selector sent to instance 
2、KVC造成的crash 
3、EXC_BAD_ACCESS 
4、KVO引起的崩溃 
5、集合类相关崩溃 
6、多线程中的崩溃 
7、Socket长连接,进入后台没有关闭 
8、Watch Dog超时造成的crash 
9、后台返回NSNull导致的崩溃,多见于Java做后台服务器开发语言
2.4 不使用第三方,如何知道已经上线的App崩溃问题, 具体到哪一个类的哪一个方法的?
https://blog.csdn.net/u013896628/article/details/53837352?utm_medium=distribute.pc_relevant_download.none-task-blog-BlogCommendFromBaidu-8.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-BlogCommendFromBaidu-8.nonecas
2.5 什么是僵尸对象?
  • 已经被销毁的对象(不能再使用的对象),内存已经被回收的对象。
2.6 什么是内存泄露?
  • 内存泄露 :一个对象不再使用,但是这个对象却没有被销毁,空间没有释放,则这个就叫做内存泄露.
  • ARC导致的循环引用 block,delegate,NSTimer等.
2.7 copy和mutableCopy 是深拷贝还是浅拷贝

所有系统容器类的copy或mutableCopy方法,都是浅拷贝.

苹果官方文档里: There are two kinds of object copying: shallow copies and deep copies. The normal copy is a shallow copy that produces a new collection that shares ownership of the objects with the original. Deep copies create new objects from the originals and add those to the new collection. 有两种类型的对象拷贝,浅拷贝和深拷贝。正常的拷贝,生成一个新的容器,但却是和原来的容器共用内部的元素,这叫做浅拷贝。深拷贝不仅生成新的容器,还生成了新的内部元素。 有官方文档为证, 我们可以得知: 浅拷贝复制容器,深拷贝复制容器及其内部元素

2.8 如下代码,会有什么问题吗?
@property (copy, nonatomic) NSMutableArray * array

使用 copy 修饰,会生成不可变数组,在添加删除数组元素时候会崩溃

3: 关键字

3.1 #include、#import、@class的区别?
1: 在C 语言中, 我们使用 #include 来引入头文件,如果需要防止重复导入需要使用#ifndef...#define...#endif.
2.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉[编译器],其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。

3.在[头文件]中,一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。

4.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。

5.如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。

所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.

3.2 OC实例变量的修饰符? 及作用范围?
@puplic: 当前类, 子类, 其他类
@protect: 当前类, 子类
@private: 当前类
@package: 介于public和private之间的,如果是在其他包中访问就是private,在当前代码中访问就是public.
3.3 @proprety的作用
1.  在.h文件中帮我们自动生成`get``set`方法声明
1.  在.m文件中帮我们生成私有的实例变量(前提是没有在.h文件中没有手动生成)
1.  在.m文件中帮我们是实现`get和set`方法的实现
3.4 @proprety 参数说明?

原子性:

属性关键字用法
atomic原子性(默认), 编译器会自动生成互斥锁, 对getter和setter方法加锁, 可以保证属性的赋值和取值是线程安全的, 但是不包括操作和访问 (ARC/MRC)
nonatomic非原子性, 一般属性都用nonatomic来修饰, 因为atomic效率低 (ARC/MRC)

读写权限

属性关键字用法
readwrite可读可写(默认),同时生成 setter 方法和 getter 方法的声明和实现
readonly只读,只生成 getter 方法的声明和实现。
readwrite可以指定生成的 setter 方法名
readwrite可以指定生成的 getter 方法名

内存管理:

属性关键字用法
assign1. 既可以修饰基本数据类型,也可以修饰对象类型;2. setter 方法的实现是直接赋值,一般用于基本数据类型(修饰对象类型时,不增加其引用计数;) ;3. 修饰基本数据类型,如 NSInteger、BOOL、int、float 等; (ARC/MRC)
retain1. MRC 下使用,ARC 下基本使用 strong; setter 方法的实现是 release 旧值,retain 新值,用于OC对象类型。 (MRC)
copy1. setter 方法的实现是 release 旧值,copy 新值,用于 NSString、block 等类型;
weak1. 只能修饰对象类型;2. ARC 下才能使用;3. 修饰弱引用,不增加对象引用计数,主要可以用于避免循环引用; (ARC)
Strong1. ARC 下才能使用;2. 原理同 retain;(ARC)
3.4 weak 和 assign 的不同点
1: weak 策略在属性所指的对象遭到摧毁时,系统会将 weak修饰的属性对象的指针指向nil,
    在OC给nil发消息是不会有什么问题的; 
2: 如果使用assign策略在属性所指的对象遭到摧毁时,属性对象指针还指向原来的对象,
由于对象已经被销毁,这时候就产生了野指针,如果这时候在给此对象发送消息,
很容造成程序奔溃assigin可以用于修饰非OC对象,而weak必须用于OC对象
3.5 代理使用 weak 还是 assign
1: 建议使用 weak, 对于weak: 指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制。

2: 可以使用assign,也有weak的功效, 对于使用 assign 修饰delegate, 在对象释放前,需要将 delegate指针设置为nil,不然会产生野指针
3.6 怎么用 copy 关键字?
  • 1: NSString、NSArray、NSDictionary 等等经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,为确保 对象中的属性值不会无意间变动,应该在设置新属性值时拷贝一份,保护其封装性

  • 2: block 也经常使用 copy 关键字,方法内部的 block 默认是 在栈区的,使用 copy 可以把它放到堆区.

  • 3: 对于 block 使用 copy 还是 strong 效果是一样的,但是 建议写上 copy,因为这样显示告知调用者“编译器会自动对 block 进行了 copy 操 作

3.7 如何让自定义类可以用 copy 修饰符?如何重写带 copy 关键字的 setter?

若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopyiog 与 NSMutableCopying 协议

// 实现不可变版本拷贝 
- (id)copyWithZone:(NSZone *)zone; 
// 实现可变版本拷贝 
- (id)mutableCopyWithZone:(NSZone *)zone; 
// 重写带 copy 关键字的 setter 
- (void)setName:(NSString *)name {
    _name = [name copy]; 
}
3.8 weak 属性需要在 dealloc 中置 nil 么
  • 1: 在ARC 环境无论是强指针还是弱指针都无需在dealloc设置为nil, ARC 会自动帮我们处理
  • 2: 即便是编译器不帮我们做这些,weak 也不需要在 dealloc 中置 nil 在属性所指的对象遭到摧毁时,属性值也会清空
3.9 OC中的NSInteger 和int 有什么区别
  • 32位操作系统时候, NSInteger 等价于 int, 即32
  • 64位操作系统时候, NSInteger 等价于 long, 即64
3.10 @synthesize 和 @dynamic 分别有什么作用
  • 1: @property 有两个对应的词,一个是@synthesize,一个是@dynamic

  • 2: 如果 @synthesize 和@dynamic都没写,那么默认的就是@syntheszie var = _var;

  • 3: @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器 会自动为你加上这两个方法

  • 4: @dynamic 告诉编译器:属性的 setter 与 getter方法由用户自己实现,不自动生成(当然对于 readonly 的属性只需提供 getter 即可)

4: OC反射机制

juejin.cn/post/710446…

5: OC中的单例

写法1: 加互斥锁,解决多线程访问安全问题

+(id)sharedInstance { 
    // 创建静态对象 防止外部访问 
    static SingleInstance *_instance; 
    @synchronized (self) { 
        // 为了防止多线程同时访问对象,造成多次分配内存空间,所以要加上线程锁。 // 
        // 相比于GCD,@synchronized比较耗性能 
        if (instance == nil) { 
            instance = [[super allocWithZone:NULL] init];  
        } 
    return _instance; 
}

写法2: GCD dispatch_onec,本身是线程安全的,保证整个程序中只会执行一次

    + (instancetype)sharedInstance {
        static ClassName *_instance;
        static dispatch_one_t oneToken;
        dispatch_once(&onetoken,^{
           _instance = [self alloc]init];
        });
        return _instance;
    }
    
    + (instancetype)allocWithZone:(NSZone *) zone{
      static dispatch_t onetoken;
      dispatch_once(&oncetoken ^{
         _instance = [super allocwithzone:zone];
      })
      retun _instance
    }

一般来说方法1要比方法2的性能要差很多, 是因为@synchronized在底层增删改查消耗了大量性能. reference: juejin.cn/post/684490…

6: NSMutableDictionary 与 NSMutableArray

6.1 NSMutableDictionary 中使用setValueForKey 和 setObjectForKey有什么区别?
  • 1: 根据官方文档说明: 一般情况下,如果给NSMutableDictionary 发送setValue 仍然是调用了 setObject方法, 如果参数 value 为 nil,则会调用removeObject 移除这个键值对;

  • 2: setObjectForKey 是 NSMutableDictionary特有的, value 不能为 nil,否则会崩溃

  • 3: setValueForKey 是KVC的,key 必须是字符串类型, setObject 的 key 可以是任意类型

6.2 NSCache 和NSDictionary 区别?
  • 1: NSCache可以提供自动删减缓存功能,而且保证线程安全,与字典不同,不会拷贝键。

  • 2: NSCache可以设置缓存上限,限制对象个数和总缓存开销。定义了删除缓存对象的时机。这个机制只对NSCache起到指导作用,不会一定执行。

  • 3: NSPurgeableData搭配NSCache使用,可以自动清除数据。

  • 4: 只有那种“重新计算很费劲”的数据才值得放入缓存。

6.3 NSArray 和 NSSet区别
  • 1: NSSet和NSArray功能性质一样,用于存储对象,属于集合。

  • 2: NSSet属于 “无序集合”,在内存中存储方式是不连续

  • 3: NSArray是 “有序集合” 它内存中存储位置是连续的。

  • 4: NSSet,NSArray都是类,只能添加对象,如果需要加入基本数据类型(int,float,BOOL,double等),需要将数据封装成NSNumber类型。

  • 5: 由于NSSet是用hash实现的所以就造就了它查询速度比较快,但是我们不能把某某对象存在第几个元素后面之类的有关下标的操作。

7:延迟调用的几个方法:

  1. performSelector方法
[self performSelector:@selector(Delay) withObject:nil afterDelay:3.0f];

2: NSTimer定时器

[NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(Delay) userInfo:nil repeats:NO];

3: sleepForTimeInterval

[NSThread sleepForTimeInterval:3.0f];

4: GCD方法

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { 
        [self Delay]; 
}); 

- (void)Delay { 
    NSLog(@"执行"); 
}

 8:分类

 什么是分类?

1.可以把类的实现放到几个不同的文件里。这样做有几个显而易见的好处。
a. 可以减少单个文件的体积
b. 可以按功能分组,放到不同的分类里,使类结构更清晰
c. 降低耦合性,同一个类可以有多个开发人员进行开发
d. 模拟多继承
e. 把静态库的私有方法公开

9.协议

9.1 什么是协议?
  • 协议:协议是一套标准,这个标准中声明了很多方法,但是不关心具体这些方法是怎么实现的,具体实现是由遵循这个协议的类去完成的。

  • 在OC中,一个类可以实现多个协议,通过协议可以弥补单继承的缺陷, 但是协议跟继承不一样,协议只是一个方法列表,方法的实现得靠遵循这个协议的类去实现。

9.2 正式协议&非正式协议?

iOS2之前是没有引⼊ 协议的,IOS2之前实现协议主要是通过给NSObject 添加 Category 类别扩展的⽅式。这种⽅式相对于iOS2之后引入的 @protocol来说叫做非正式协议. 非正式协议都是以NSObjectCategory 的⽅式实现的。所以所有基于NSObject 的⼦类都可以使⽤定义的非正式协议.

  • 非正式协议:凡是在NSObject或其子类 Foundation 框架中的类增加类别(分类),都是非正式协议
  • 正式协议: 对于@protocol来说, 编译器会在编译期检查语法错误, 非正式协议则不会检查是否实现.
9.3 如何实现多继承
  1. 类别
  2. 协议
  3. 消息转发

10: OC 的动态特性

10.1 为什么说OC是一门动态语言?
  • 动态语言:是指程序在运行时可以改变其结构,新的函数可以被引进,已有的函数可以被删除等在结构上的变化
  • 动态类型语言: 就是类型的检查是在运行时做的。
10.2 OC动态类型的三个方面?
  • 动态类型(Dynamic typing): 最终判定该类的实例类型是在运行期间
  • 动态绑定(Dynamic binding):在运行时确定调用的方法
  • 动态加载(Dynamic loading):在运行期间加载需要的资源或可执行代码
10.3 动态绑定?
  • 动态绑定 将调用方法的确定也推迟到运行时。OC可以先跳过编译,到运行的时候才动态地添加函数调用,在运行时才决定要调用什么方法,需要传什么参数进去,这就是动态绑定。

  • 在编译时,方法的调用并不和代码绑定在一起,只有在消实发送出来之后,才确定被调用的代码。通过动态类型和动态绑定技术,

11: UI

11.1 cocoa 和 cocoa touch是什么?区别?

  • Cocoa包含Foundation和AppKit框架,可用于开发Mac OS X系统的应用程序。
  • Cocoa Touch包含Foundation和UIKit框架,可用于开发iPhone OS系统的应用程序。
  • Cocoa是 Mac OS X 的开发环境,Cocoa Touch是 iPhone OS的开发环境。

12: 谓词?

12.1 什么是谓词?

谓词(NSPredicate)是OC针对数据集合的一种逻辑帅选条件,类似一个过滤器,简单实实用代码如下:

Cat * c1 = [Cat personWithName:@"EB" Age:20]; 
Cat * c2 = [Cat personWithName:@"SB" Age:30]; 
Cat * c3 = [Cat personWithName:@"DB" Age:10]; 
NSArray * cats = @[c1, c2, c3]; //定义谓词对象,谓词对象中包含了过滤条件 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age < 30"]; 
//使用谓词条件过滤数组中的元素,过滤之后返回查询的结果 
NSArray *array = [cats filteredArrayUsingPredicate:predicate];

13: 设计模式:

13.1 什么是类工厂方法?

类工厂方法就是用来快速创建对象的类方法, 他可以直接返回一个初始化好的对象,具备以下特征:

  • 一定是类方法
  • 返回值需要是 id/instancetype 类型
  • 规范的方法名说说明类工厂方法返回的是一个什么对象,一般以类名首字母小写开始;

比如系统 UIButton 的buttonWithType 就是一个类工厂方法:

// 类工厂方法 
+ (instancetype)buttonWithType:(UIButtonType)buttonType; 
// 使用 
+ UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];

14: 什么是糖衣语法?

糖衣语法,又叫‘语法糖’、‘语法盐’等等,是由英国计算机科学家彼得·约翰·兰达(Peter J.Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

糖衣语法在各种语言中都有出现,最常用的就是数组的[ ]操作符的下标访问以及{ }操作符对数组的初始化,例如C语言中可以通过下标访问数组元素,这种类似[ ]和{ }操作符的符合程序员思维的简单表示方法就是所谓的糖衣语法:

int a[3] = {1,2,3};
int b = a[2];

[ ]和{ }在JSON数据格式中最常见,[ ]一般封装一个数组,{ }一般封装一个整体对象。另外在OC中用到语法糖的一个非常重要的类型是NSNumber,一个将基本数据类型封装起来的对象类型,基本数据类型像‘@3’这种表达就是NSNumber的语法糖,也推荐这种用法。 www.jianshu.com/p/0f0f63739…

15: Git区别

  • svn 和 git 都是用来对项目进行版本控制以及代码管理的.可以监测代码及资源的更改变化.有利于实现高效的团队合作;

  • svn 是集中式的,集中式是指只有一个远程版本库,git 是分布式的,分布式有本地和远程版本库,本地仓库都保留了整个项目的完整备份;
    如果存储远程版本库的服务器挂了,所有人的代码都无法提交,甚至丢失版本库, git则因为有本地版本库而不会有这个问题。

  • 由于两者的架构不同,git 和 svn 的分支也是不同的, svn 的分支是一个完整的目录,包含所有的实际文件,和中心仓库是保持同步的,如果某个团队成员创建新的分支,那么会同步到所有的版本成员中,所有人都会收到影响. 而 git下创建的分支合并前是不会影响到任何人的.创建分支可以在本地脱机进行任何操作.测试无误后在合并到主分支,然后其他成员才可以看得到.

16: 数据结构

16.1 OC中有二维数组吗? 如何实现?

OC中没有二维数组, 可以通过一维数组嵌套来实现二维数组;

// 字面量定义 
NSArray * array = @[ 
                    @[@1,@2,@3,@4,@5], 
                    @[@11,@12,@13,@14,@15], 
                    @[@21,@22,@23,@24,@25], 
                    @[@31,@32,@33,@34,@35], 
                    @[@41,@42,@43,@44,@45], 
                    ]; 
                 
// 访问 
NSLog(@"%@",array[1][1]);

17:KVC中的集合运算符

  • 简单集合运算符:@avg、@sum、@max、@min、@count (只能用在集合对象中,对象属性必须为数字类型)

  • 对象操作符: @unionOfObjects:返回指定属性的值的数组,不去重
    @distinctUnionOfObjects:返回指定属性去重后的值的数组

  • 数组 / 集体操作符:跟对象操作符很相似,只不过是在NSArray和NSSet所组成的集合中工作的。@unionOfArrays:返回一个数组,值由各个子数组的元素组成,不去重 @distinctUnionOfArrays:返回一个数组,值由各个子数组的元素组成,去重 @distinctUnionOfSets:和@distinctUnionOfArrays差不多, 只是它期望的是一个包含着NSSet对象的NSSet,并且会返回一个NSSet对象。因为集合不能有重复的值,所以只有distinct操作。

Reference: