美文网首页
OC 和 Swift 问题 (随时补充)

OC 和 Swift 问题 (随时补充)

作者: 一欧Yiou | 来源:发表于2019-01-02 18:02 被阅读5次

问: 关键字static的作用是什么?

    1. 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
    1. 在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
    1. 在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;

问: 关键字const是什么含义? 分别解释下列语句中const的作用?

const int a;
int const a;
const int *a;
int * const a;
int const * a const;

含义

    1. 欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
    1. 对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
    1. 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
    1. 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

作用

const int a;            //a是一个常整型数
int const a;            //a是一个常整型数
const int *a;           //a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)
int * const a;          //a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)
int const * a const;    //a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)

问: 使用nonatomic一定是线程安全的吗?

    1. nonatomic: 非原子性,set方法的实现不加锁,不安全,性能高
    1. atomicatomic性能低,atomic通过锁定机制来确保其原子性,但只是读/写安全,不能绝对保证线程的安全,当多线程同时访问的时候,会造成线程不安全。可以使用线程锁来保证线程的安全。

问: 对于语句NSString *obj = [[NSData alloc] init]; ,编译时和运行时obj分别是什么类型?

    1. 编译时是NSString类型
    1. 运行时是NSData类型

问: Objective-C如何对内存管理的,说说你的看法和解决方法?

    1. 每个对象都有一个引用计数器,每个新对象的计数器是1,当对象的计数器减为0时,就会被销毁
    1. 通过retain可以让对象的计数器+1、release可以让对象的计数器-1
    1. 还可以通过autorelease pool管理内存
    1. 如果用ARC,编译器会自动生成管理内存的代码

注意:不管是MRC还是ARC都是在编译时完成的


问: iOS数据持久化有哪些?

为何要持久化:iOS 开发可以没有持久化,持久化更多的是业务需求;比如记录用户是否登陆,下次进应用不需要再登陆。
因为 iOS沙盒机制,所以持久化分为两类:沙盒内沙盒外

    1. 沙盒内
      (1) NSKeyedArchiver: 只要遵循了 NSCoding 协议并正确实现了initWithCoderencodeWithCoder 方法的类都可以通过NSKeyedArchiver 来序列化。
      归档使用 archiveRootObject ,解归档使用 unarchiveObjectWithFile ;需要指定文件路径。
      (2) NSUserDefaults: [NSUserDefaults standardUserDefaults]获取NSUserDefaults对象,以key-value方式进行持久化操作。
      (3) plist: 写入使用writeToFile,读取使用xxxWithContentsOfFile;需要指定文件路径。
      (4) 数据库: sqliteCoreDataRealm
      (5) 文件: 这里要和plist区分一下,plist方式是字典/数组数据格式写入文件;而这里的文件方式不限数据格式。
    1. 沙盒外
      沙盒内的方式在应用被删除后数据都会丢失,如果想要不丢失则需要使用KeyChain
      KeyChain本质是一个sqlite数据库,其保存的所有数据都是加密过的。
      KeyChain分为私有和公有,公有则需要指定group,一个group中的应用可以共享此KeyChain
      使用KeyChain过程中要理解下面几个问题:
      ①:自己使用的KeyChain和系统自带的KeyChain数据是隔离的,内部应该是不同数据库文件;
      ②:KeyChain数据可备份到iCloud中;
      ③:不需要联网,也不用登陆iCloud账号;一个设备一个sqlite数据库,但是不同应用组不共享数据;
      ④:要在另一台设备上使用当前设备存储的KeyChain信息,需要当前设备进行数据备份,再在另一设备上复原数据;比较常用的是iCloud备份方式;
      ⑤:系统自带的KeyChain中账号密码分类数据可在系统设置->账号与密码里面看到,你退出iCloud账号还是存在,只是iCloud会帮你备份如果你设置了的话;这个和照片是一样的道理。

问: id和NSObject*的区别?

  • id可以指向OC中的任何对象,而NSObject*只能指向NSObject及子类对象

问: strong 和 weak 的区别?


问: (堆和栈) 哪些数据是放在堆上的,哪些是放在栈上的?

  • 栈:由系统自动分配,速度较快,不会产生内存碎片,
  • 堆:是由alloc分配的内存,速度比较慢,而且容易产生内存碎片,不过用起来最方便。

问: UITableView 优化?

    1. cell复用
      我们经常在注意 cellForRowAtIndexPath: 中为每一个 cell 绑定数据,实际上在调用 cellForRowAtIndexPath: 的时候 cell 还没有被显示出来,为了提高效率我们应该把数据绑定的操作放在 cell 显示出来后再执行,可以在tableView:willDisplayCell:forRowAtIndexPath:(以后简称willDisplayCell)方法中绑定数据。
      注意 willDisplayCellcelltableview 展示之前就会调用,此时 cell 实例已经生成,所以不能更改 cell 的结构,只能是改动 cell 上的 UI 的一些属性(例如 label 的内容等)。
    1. cell高度的计算
      (1)定高的 cell,应该采用如下方式:self.tableView.rowHeight = 88;
      (2)动态高度的cell:tableView: tableViewheightForRowAtIndexPath:,该方法实现后,上面的 rowHeight 的设置将会变成无效。在这个方法中,我们需要提高 cell 高度的计算效率,来节省时间。
      自从 iOS8 之后有了 self-sizing cell 的概念,cell 可以自己算出高度,使用 self-sizing cell 需要满足以下三个条件:
      ① 使用 Autolayout 进行 UI 布局约束(要求 cell.contentView 的四条边都与内部元素有约束关系)。
      ② 指定 TableViewestimatedRowHeight 属性的默认值。
      ③ 指定 TableViewrowHeight 属性为 UITableViewAutomaticDimension
    1. 渲染
      (1)当有图像时,预渲染图像,在 bitmap context 先将其画一遍,导出成 UIImage 对象,然后再绘制到屏幕,这会大大提高渲染速度。具体内容可以自行查找“利用预渲染加速显示 iOS 图像”相关资料。
      (2)渲染最好时的操作之一就是混合( blending )了,所以我们不要使用透明背景,将 cellopaque 值设为 Yes,背景色不要使用 clearColor,尽量不要使用阴影渐变等。
      (3)由于混合操作是使用 GPU 来执行,我们可以用 CPU 来渲染,这样混合操作就不再执行。可以在 UIViewdrawRect 方法中自定义绘制。
    1. 减少视图的数目
      我们在 cell 上添加系统控件的时候,实际上系统都会调用底层的接口进行绘制,大量添加控件时,会消耗很大的资源并且也会影响渲染的性能。当使用默认的 UITableViewCell 并且在它的 ContentView 上面添加控件时会相当消耗性能。所以目前最佳的方法还是继承 UITableViewCell ,并重写 drawRect 方法。
    1. 减少多余的绘制操作
      在实现 drawRect 方法的时候,它的参数 rect 就是我们需要绘制的区域,在 rect 范围之外的区域我们不需要进行绘制,否则会消耗相当大的资源。
    1. 不要给cell动态添加subView
      在初始化 cell 的时候就将所有需要展示的添加完毕,然后根据需要来设置 hide 属性显示和隐藏。
    1. 异步化UI,不要阻塞主线程
      我们时常会看到这样一个现象,就是加载时整个页面卡住不动,怎么点都没用,仿佛死机了一般。原因是主线程被阻塞了。所以对于网路数据的请求或者图片的加载,我们可以开启多线程,将耗时操作放到子线程中进行,异步化操作。这个或许每个 iOS 开发者都知道的知识,不必多讲。
    1. 滑动时按需加载对应的内容
      如果目标行与当前行相差超过指定行数,只在目标滚动范围的前后指定3行加载。
      滑动很快时,只加载目标范围内的cell,这样按需加载(配合SDWebImage),极大提高流畅度。

问: 消息列表页面如何优化?

首先我们发消息时候观察一下消息列表的特性,当发送一条消息时候,消息的数量会变化,列表会出现在最上边的位置,列表内的内容会发生变化。从消息列表的特性,我们就可以分析出要优化的点了。通过这些点,我们做了一些优化:

    1. 如果列表消息从没显示过需要刷新列表,创建好一个cell后,将cell插入到第一位上,cell插入的性能要高于刷新tableview的性能。
    1. 如果消息已经显示过了,但是并不是第一位,则需要刷新列表。
    1. 如果消息已经显示,并且是第一位,则只需要cell的内容变化。
    1. 只修改cell里的内容,不进行刷新cell整体,这里要注意的是,一定要最小化刷新。刷新点越小,性能损耗越小。我们项目架构是MVVM,采用了ReactiveCocoa框架,针对每个cell上的可变化的控件数据进行了监听,每一个cell上对应一个vm,这样当vm上的数据变化时候,cell上的数据也就跟着变了。做到了最小化刷新。
    1. 避免使用autolayout计算位置,这个很重要,在性能要求高的情况下,autolayout计算会很耗时间,尤其在算tableview高度的时候可见一斑。可喜的是消息列表的高度是固定的,所以在计算高度时候我们并未花费时间。
    1. 使用(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath而不使用-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier来查找cell,因为下边的方法会多查一次,耗时更长一点。
    1. cellForRowAtIndexPath方法只负责创建cell,willDisplayCell方法才给cell进行赋值操作。从方法名字就可以看出来原因
    1. 当来消息轰炸时候,必然会是不同的人发来的消息,会导致tableview不可避免的刷新,如果不加处理必然会卡顿,要知道,机器也是有瓶颈的。这里我们做的优化是根据cpu的使用率选择性的刷新tableview。后来我们发现微信也是有这个现象,并不是实时的刷新,我们猜测也是类似处理。
    1. 重绘制系统控件,相信你也发现了消息列表里,主要有两个控件,一个是头像,一个是label。而系统的UIImageView用来显示头像,未免有点重。我们的处理是使用UIView,设置Viewlayer.content来处理。针对layer层做的setImageWithUrl的第三方库也不少,大家可以自行查询。另一个就是label,如果你能集成UIView自己绘制一个label,我想也许会有一点效果。

问: 聊天界面如何优化?

聊天界面的优化算是比较繁琐的了,但是优化点跟回话列表的优化差不多。上边提到回话列表里最耗时的tableview的高度是固定的,而聊天界面的几乎每条消息的高度都可能不一样,所以我们在优化聊天界面时候最重要的一点就是计算tableviewcell的高度。而我们在计算tableview的高度是怎么做的呢?

主要有两个准则:
(1) 第一个是能在后台线程执行的都放在后台线程里。
(2) 第二个计算高度要放在显示之前。

    1. 巧妙的选择控件。(比如上个问题提到的用UIViewlayer.content来代替UIImageView, 图片加点击也可以用view,然后监听viewtouch事件,像button这种重量级的控件在性能为主的app面前,我对他们都是弃之如敝履。)
    1. 减少使用layer层的cornerRadiusmask等圆角的绘制,这会引发离屏渲染,增加cpu的占用率。如果业务需要的话,我们可以通过UIBezierPathdrawInRect它。
    1. 避免设置透明
    1. 避免autolayout设定控件位置
    1. 尽可能的减少视图的层级,如果你能把所有的控件都绘制到一个View上,可想而知性能会爆棚。

问: Swift的可选类型?


问: Swift 中 Struct 和 Class的区别 ?

    1. property初始化的不同:
      主要的差別就是 class 在初始化时不能直接把 property 放在 默认的constructor 的参数里,而是需要自己创建一个带参数的 constructor
    1. 变量赋值方式不同(深浅copy)
      struct 赋值“=”的时候,会copy一份完整相同的內容给另一個变量 -> 【开辟了新的内存地址】 (深拷贝)
      class 赋值“=”的时候,不会copy一份完整的内容给另一個变量,只是增加了原变量内存地址的引用而已 -> 【没有开辟了新的内存地址】 (浅拷贝)
    1. immutable 变量
      Swift 语言的特色之一就是可变动内容和不可变内容用 varlet 來甄别,如果初始为let的变量再去修改会发生编译错误。
      struct也遵循这一特性
      class不存在这样的问题
    1. structclass 的差別是 structfunction 要去改变 property 的值的时候要加上 mutating,而 class 不用。
    1. struct不能继承,class可以继承。
    1. struct分配在栈中,class分配在堆中。

Swift 用 Struct 作为数据模型时需要注意什么问题?

优点:
    1. 安全性:因为 Struct 是用值类型传递的,它们没有引用计数。
    1. 内存:由于他们没有引用数,他们不会因为循环引用导致内存泄漏。
    1. 速度:值类型通常来说是以栈的形式分配的,而不是用堆。因此他们比 Class 要快很多!
    1. 拷贝:Objective-C 里拷贝一个对象,你必须选用正确的拷贝类型(深拷贝、浅拷贝),而值类型的拷贝则非常轻松!
    1. 线程安全:值类型是自动线程安全的。无论你从哪个线程去访问你的 Struct ,都非常简单。
缺点: (需要注意的地方)
    1. Objective-C:当你的项目的代码是 SwiftObjective-C 混合开发时,你会发现在 Objective-C 的代码里无法调用 SwiftStruct。因为要在 Objective-C 里调用 Swift 代码的话,对象需要继承于 NSObject
      Struct 不是 Objective-C 的好朋友。
    1. 继承:Struct 不能相互继承。
    1. NSUserDefaultsStruct 不能被序列化成 NSData 对象。
总结:如果模型较小,并且无需继承、无需储存到 NSUserDefault 或者无需 Objective-C 使用时,建议使用 Struct

相关文章

  • OC 和 Swift 问题 (随时补充)

    问: 关键字static的作用是什么? 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量...

  • iOS中扩大button响应区域

    一、OC版 OC版使用: OC版实现: 二、swift版 swift版使用: 补充:由于BEButton继承UIB...

  • iOS OC与Swift混编

    一、Swift使用OC类的桥文件 二、OC使用Swift类的桥文件 三、配置信息 四、补充

  • oc Swift 混编

    oc Swift 混编 oc 项目 混编Swift1.1 oc 调用 Swift 的类 和 方法步骤: ...

  • Object-c和swift混编问题

    为什么要学习这个问题呢? 随着Swift的改进和Swift 越来越多,越来越多的OC工程使用OC+Swift 混编...

  • iOS中Objective-C和Swift混编及第三方框架相互调

    本文将详细介绍一下OC和swift混编问题,其中涉及两大部分:1)oc项目中混编swift的实现; 2)oc或者s...

  • OC和Swift混编

    OC和Swift的混编,分为两种情况: OC项目中嵌入Swift文件 Swift项目中嵌入OC文件 先来看OC项目...

  • OC Swift文件混编

    一.Swift 类可以继承 OC 类,OC 类不能继承 Swift 类。 二.Swift 和 OC 混编 三.两个...

  • iOS 多Target若干问题处理

    OC混编Swift项目中的头文件引入问题 问题背景 在OC中导入-Swift.h文件,切换Target时报错 个人...

  • Swift和OC混合开发

    在swift项目上的Swift和OC混合开发 1、Swift调OC方法: (1)、直接新建OC项目会自动创建桥梁文...

网友评论

      本文标题:OC 和 Swift 问题 (随时补充)

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