1.Class 中包含属性 Name 如何定义为对外只读对内可读写?
在头文件中将属性定义为readonly, 在.m文件中将属性重新定义为readwrite
2.什么情况使用 weak 关键字,相比 assign 有什么不同?
- 在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性
- 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。在下文也有论述:
不同点:
- weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似,然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
- assigin 可以用非 OC 对象,而 weak 必须用于 OC 对象
3.这个写法会出什么问题: @property (copy) NSMutableArray *array;
添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃。
//如:-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460
// copy后返回的是不可变对象(即 arr 是 NSArray 类型,NSArray 类型对象不能调用 NSMutableArray 类型对象的方法)
原因:是因为 copy 就是复制一个不可变 NSArray 的对象,不能对 NSArray 对象进行添加/修改。
4.举例说明浅复制和深复制的区别?
浅复制 你和你的影子 你挂了 他也挂了
深复制 你和你的克隆体 你挂了 他还存在
浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存
5.iOS 开发中数据持久性有哪几种?你用到哪些?
据存储的核心都是写文件。
- 属性列表:只有NSString、NSArray、NSDictionary、NSData可writeToFile;存储依旧是plist文件。plist文件可以存储的7中数据类型:array、dictionary、string、bool、data、date、number。
- 对象序列化(对象归档):对象序列化通过序列化的形式,键值关系存储到本地,转化成二进制流。通过runtime实现自动化归档/解档,请参考这个文章。实现NSCoding协议必须实现的两个方法:
- 编码(对象序列化):把不能直接存储到plist文件中得到数据,转化为二进制数据,NSData,可以存储到本地;
- 解码(对象反序列化):把二进制数据转化为本来的类型。
- SQLite 数据库:大量有规律的数据使用数据库。
- CoreData :通过管理对象进行增、删、查、改操作的。它不是一个数据库,不仅可以使用SQLite数据库来保持数据,也可以使用其他的方式来存储数据。如:XML。
6.UITableViewCell 上有个 UILabel,显示 NSTimer 实现的秒表时间,手指滚动 cell 过程中,label 是否刷新,为什么?
这是否刷新取决于timer加入到Run Loop中的Mode是什么。Mode主要是用来指定事件在运行循环中的优先级的,分为:
- NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
- UITrackingRunLoopMode:ScrollView滑动时会切换到该Mode
- UIInitializationRunLoopMode:run loop启动时,会切换到该mode
- NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
苹果公开提供的Mode有两个:
- NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
- NSRunLoopCommonModes(kCFRunLoopCommonModes)
- 在编程中:如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。当我们滚动的时候,也希望不调度,那就应该使用默认模式。但是,如果希望在滚动时,定时器也要回调,那就应该使用common mode。
7.UIView 和 CALayer 之间的关系?
- 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
- 在 View显示的时候,UIView 做为 Layer 的 CALayerDelegate,View 的显示内容由内部的 CALayer 的 display
- CALayer 是默认修改属性支持隐式动画的,在给 UIView 的 Layer 做动画的时候,View 作为 Layer 的代理,Layer 通过 actionForLayer:forKey:向 View请求相应的 action(动画行为)
- layer 内部维护着三分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树), Render Tree (渲染树),在做 iOS动画的时候,我们修改动画的属性,在动画的其实是 Layer 的 presentLayer的属性值,而最终展示在界面上的其实是提供 View的modelLayer
- 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以
8.UIWebView 有哪些性能问题?有没有可替代的方案。
使用UIWebView来显示图片和动态图,会占用很多内存,内存占用多了之后就会出现卡顿。如果播放的图片比较少占的内存比较小或者比较常用,可以选择用imageNamed:方式获取图片。
9.有 a、b、c、d 4个异步请求,如何判断 a、b、c、d都完成执行?如果需要 a、b、c、d顺序执行,该如何实现?
123456789101112131415161718 > dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);>> dispatch_group_t group = dispatch_group_create();>> dispatch_group_async(group, queue, ^{ /*任务a */ });>> dispatch_group_async(group, queue, ^{ /*任务b */ });>> dispatch_group_async(group, queue, ^{ /*任务c */ });>> dispatch_group_async(group, queue, ^{ /*任务d */ });>> dispatch_group_notify(group,dispatch_get_main_queue(), ^{>> // 在a、b、c、d异步执行完成后,会回调这里>> });>
>
10.Scoket 连接和 HTTP 连接的区别?
- HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。
- HTTP连接服务端无法主动发消息,Socket连接双方请求的发送先后限制。这点就比较重要了,因为它将决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,在客户端还没发送消息给服务端前,服务端无法推送消息给客户端。必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。
11.如何把一个包含自定义对象的数组序列化到磁盘?
- 自定义对象需要实现NSCoding协议
123456789101112131415161718192021222324 > - (void)viewDidLoad{> [super viewDidLoad];> User user = [User new];> Acac= [Acnew];> NSArray userArray = @[user, account];> // 存到磁盘> NSData tempArchive = [NSKeyedArchiver archivedDataWithRootObject: userArray];> }>> // 代理方法> -(instancetype)initWithCoder:(NSCoder )coder{> self = [super initWithCoder:coder];> if (self) {> self.user = [aDecoder decodeObjectForKey:@"user"];> self.ac= [aDecoder decodeObjectForKey:@"account"];> }> return self;> }> // 代理方法> -(void)encodeWithCoder:(NSCoder )aCoder{> [aCoder encodeObject:self.user forKey:@"user"];> [aCoder encodeObject:self.acforKey:@"account"];> }>或者
12345678910 > +(BOOL)writeToPlistFile:(NSDictionary*)settings fileName:(NSString*)filename{>> NSData * data = [NSKeyedArchiver archivedDataWithRootObject:settings];> NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);> NSString * documentsDirectory = [paths objectAtIndex:0];> NSString * path = [documentsDirectory stringByAppendingPathComponent:filename];> BOOL didWriteSuccessfull = [data writeToFile:path atomically:YES];> return didWriteSuccessfull;> }>
12.iOS 的沙盒目录结构是怎样的? App Bundle 里面都有什么?
沙盒结构
- Application:存放程序源文件,上架前经过数字签名,上架后不可修改
- Documents:常用目录,iCloud备份目录,存放数据,这里不能存缓存文件,否则上架不被通过
- Library
- Caches:存放体积大又不需要备份的数据,SDWebImage缓存路径就是这个
- Preference:设置目录,iCloud会备份设置信息
- tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能
App Bundle
- Info.plist:此文件包含了应用程序的配置信息.系统依赖此文件以获取应用程序的相关信息
- 可执行文件:此文件包含应用程序的入口和通过静态连接到应用程序target的代码
- 资源文件:图片,声音文件一类的
- 其他:可以嵌入定制的数据资源
13.如何把一张大图缩小为 1/4 大小的缩略图?
123 > UIImagePNGRepresentation(UIImage __nonnull image);> UIImageJPEGRepresentation(UIImage __nonnull image, CGFloat compressionQuality);>
12345678910111213141516 > //等比例缩放图片> +(UIImage *)cropImage:(UIImage *)image scale:(CGFloat)scale{> CGSize newSize = CGSizeMake(image.size.widthscale, image.size.heightscale);>> UIGraphicsBeginImageContext(newSize);>> [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];>> image = UIGraphicsGetImageFromCurrentImageContext();>> UIGraphicsEndImageContext();>> return image;>> }>
14.Objective-C 的 class 是如何实现的?Selector 是如何被转化为 C 语言的函数调用的?
Class
是一个objc_class
结构类型的指针;类是通过
struct objc_class
结构实现的
12 > typedef struct objc_class *Class;>
15.dispatch_async 与 dispatch_sync 解释一下?
asyne 是异步 sync 是同步
|
|
打印结果是?
132
把 async 换成 sync 打印结果是?
打印结果是1 然后崩溃了(线程死锁)
dispatch_async中加入dispatch_get_main_queue中,是异步运行中把主队列中的运行任务放到主线程中去运行。
而dispatch_sync中的dispatch_get_main_queue,是在主线程中运行主队列,当把主队列中得任务放到主线程时,会和dispatch_sync进行线程争夺。这时就会产生线程死锁。