Day6

作者: Jean_Lina | 来源:发表于2020-07-29 14:14 被阅读0次

1:为什么说Objective-C 是一门动态的语言?
Objective-C 可以通过Runtime 这个运行时机制,在运行时动态的添加变量、方法、类等,所以说Objective-C 是一门动态的语言。

2:讲一下MVC和MVVM?
MVC设计模式
MVC是一种架构模式,M表示Model,V表示视图View,C表示控制器Controller。
Model:存储、定义、操作数据;
View:展示数据给用户,和用户进行操作交互;
Controller:Model和View的协调者,把Model中的数据拿过来给View用。
MVC(Model View Contrller)很好的分离了视图层和业务层,实现解耦。

MVVM设计模式
Model:存储、定义、操作数据;
View:就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。
ViewModel:View和Model层的粘合剂,把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。
MVVM(Model View ViewModel)比MVC更加释放控制器臃肿,将一部分业务逻辑处理、数据缓存、网络请求从控制器里面搬运到ViewModel中。

3:为什么代理要用weak?
(1)避免循环引用
(2)当使用weak修饰的属性,当对象释放的时候,系统会对属性赋值nil。

4:delegate和dataSource有什么区别?
delegate:表示代理,代理可以让A对象通知B对象,我(A)发生的变化,前提B是A的代理,并且实现了A的代理方法。
代理又叫委托,是一种设计模式.
代理是对象与对象之间的通信交互,代理解除了对象之间的耦合性。

dataSource:表示数据源,如果A对象声明了数据源,当我们创建A对象的时候,我们就该实现数据源,来告诉A,他所需要的一些数据。
例如:tableView数据源方法,需要告诉它,我要实现几组cell,每组cell多少行,实现cell什么样式,什么内容

5:协议的基本概念和协议中方法默认是什么类型
OC中的协议是一个方法列表,可以被任何类使用,但它并不是类,自身不会实现方法。
默认是可选的。

6:delegate、NSNotification、Block和KVO的区别
代理是一对一的关系
Block是一对一的关系
通知是一对多的关系

效率:delegate比NSNOtification高;
delegate和Block一般是一对一的通信;都可以用来做倒序传值的,注意避免循环引用。
代理使用weak修饰,delegate需要定义协议方法,代理对象实现协议方法,并且需要建立代理关系才可以实现通信;
Block使用的是copy修饰,更加简洁,不需要定义繁琐的协议方法,保存的是一段代码,其实也就是一个函数。
KVO:观察者模式,通常只监听某一个对象的多个属性,如果属性太多,方法会很乱。在不需要的时候,都需要释放。如果不释放,会崩溃。

7:nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?
atomic:原子属性,为setter方法加锁(默认就是atomic),线程安全,需要消耗大量的CPU资源,效率低
nonatomic:非原子属性,不会为setter方法加锁,非线程安全,适合内存小的移动设备,效率高
atomic:不能绝对保证线程的安全,当多线程同时访问的时候,会造成线程堵塞。可以使用线程锁来保证线程的安全。

8:属性的实质是什么?包括哪几个部分?
属性是描述类的特征,具备什么特性。
包括三个部分:带下划线的成员变量,getter、setter方法。

属性默认的关键字都有哪些?
在声明property时,如果不指定关键字,编译器会为property生成默认的关键字。
对应基本数据类型,默认关键字为atomic,assign,readwrite。
对应对象类型,默认关键字为atomic,strong,readwrite。

属性和成员变量的区别
@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法

9: @dynamic关键字和@synthesize关键字是用来做什么的?
@dynami:修饰的属性,其getter和setter方法编译器是不会自动帮你生成,必须自己是实现的。
@synthesize:修饰的属性,其getter和setter方法编译器是会自动帮你生成,不必自己实现。

10:objc使用什么机制管理对象内存?
使用引用计数器来管理内存的。
当对象的引用计数器为0的时候,对象就会被释放。

11:NSString为什么要用copy关键字,如果用strong会有什么问题?(使用copy和strong是看情况而定的)
对源头是NSMutableString的字符串,strong仅仅是指针引用,增加了引用计数器。在源头改变的时候,用strong方式声明的变量(无论被赋值的变量是可变的还是不可变的),它也会跟着源头改变;
而copy声明的变量,它不会跟着源头改变,它实际上是深拷贝。
对源头是NSString的字符串,无论是strong声明的变量还是copy声明的变量,当源头字符串重新指向新值的时候,它们还是指向最初值,其实二者都是指针引用,也就是浅拷贝。

如果拷贝的对象是可变的,使用copy修饰的会重新拷贝一份,是新的内存地址
如果拷贝的对象是不可变的,那么使用copy属性只是指针拷贝,对应的是同一块内存地址
strong是指针引用,是在原来的地址上进行强引用,值会跟随对象值的变化而变化。

  • copy与mutableCopy 要看拷贝的对象是不可变的还是可变的

  • 如果对象是可变的,不管使用copy还是mutableCopy,都会开辟新的内存空间,都是深拷贝。 比如: 对mutableString进行copy或者mutableCopy

  • 如果拷贝的对象是不可变的, 那么copy只是浅拷贝,不会开辟新的内存,mutableCopy是深拷贝会开辟新的内存。

@property (nonatomic, strong) NSString   *str1;
@property (nonatomic, copy)   NSString   *str2;

- (void)test1 {
    NSMutableString *mutableString = [NSMutableString stringWithFormat:@"hello"];
    self.str1 = mutableString;
    self.str2 = mutableString;
    [mutableString appendString:@"world"];
}
运行结果:
(lldb) p mutableString
(__NSCFString *) $4 = 0x00000002814841b0 @"helloworld"
(lldb) p _str1
(__NSCFString *) $5 = 0x00000002814841b0 @"helloworld"
(lldb) p _str2
(NSTaggedPointerString *) $6 = 0xd0261523e8718516 @"hello"
mutableString、_str1内存地址和value一样
_str2新开辟了一块内存,内存不随mutableString改变。

- (void)test2 {
    NSString *originString = [NSString stringWithFormat:@"hello"];
    self.str1 = originString;
    self.str2 = originString;
}
运行结果:
(lldb) p originString
(NSTaggedPointerString *) $8 = 0xd0261523e8718516 @"hello"
(lldb) p _str1
(NSTaggedPointerString *) $9 = 0xd0261523e8718516 @"hello"
(lldb) p _str2
(NSTaggedPointerString *) $10 = 0xd0261523e8718516 @"hello"

- (void)copyWithMutableCopy1 {
    NSString *originString = @"haha";
    NSString *copyString = [originString copy]; //浅拷贝
    NSString *mutableCopyString = [originString mutableCopy]; //深拷贝
}
运行结果:
(lldb) p originString
(__NSCFConstantString *) $11 = 0x0000000105a2abf8 @"haha"
(lldb) p copyString
(__NSCFConstantString *) $12 = 0x0000000105a2abf8 @"haha"
(lldb) p mutableCopyString
(__NSCFString *) $13 = 0x0000000281485c80 @"haha"

- (void)copyWithMutableCopy2 {
    NSMutableString *originString = [NSMutableString stringWithString:@"hello"];
    NSString *copyString = [originString copy]; //深拷贝
    NSString *mutableCopyString = [originString mutableCopy]; //深拷贝
    [originString appendString:@"world"];
}
运行效果:
(lldb) p originString
(__NSCFString *) $14 = 0x0000000281480c60 @"helloworld"
(lldb) p copyString
(NSTaggedPointerString *) $15 = 0xd0261523e8718516 @"hello"
(lldb) p mutableCopyString
(__NSCFString *) $16 = 0x000000028157ff90 @"hello"

12:为什么IBOutlet修饰的UIView也适用weak关键字?
我们将控件拖到Storyboard上,相当于创建了一个对象,而这个对象是加到视图控制器的view上,存放在view的subviews数组中,view对其子控件之前的关系是强引用。当我们使用Outlet属性的时候,这个Outlet属性是有view来进行强引用的。我们是在viewController中仅仅对其进行使用,没有必要拥有它,所以使用weak进行修饰。

13:可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别?如果是集合是内容复制的话,集合里面的元素也是内容复制么?
使用copy时,可变集合的指针地址以及内存地址都不相同 属于深复制。不可变集合的指针地址不一样,内存地址一样 属于浅复制
使用mutableCopy时,无论是可变集合还是不可变集合的指针地址和内存地址都不同 都属于深复制。

14: 用StoryBoard开发界面有什么弊端?如何避免?
使用简单逻辑页面的跳转是可以使用sb的,开发比较块。
(1)不适合多人合作开发;
(2)不利于版本更新和后期的维护;
(3)对于业务逻辑比较复杂的时候,开发起来比较慢。
可以使用xib来代替,处理复杂的业务逻辑界面,可以使用纯代码编写。

15: 数据持久化的几个方案
UserDefaults、钥匙串、文件读写

16: 如何使用队列来避免资源抢夺?
(1)可以使用线程锁的来绑定。
(2)可以使用串行队列来完成。
如:fmdb就是使用FMDatabaseQueue,来解决多线程抢夺资源。

17: 实现description方法能取到什么效果?
description是NSObject的一个实例的方法,返回的是一个NSString。
description方法默认实现是返回类名和对象的内存地址

相关文章

网友评论

      本文标题:Day6

      本文链接:https://www.haomeiwen.com/subject/cohhrktx.html