2018-03-22

美图

1.自我介绍

2.介绍一下自己做的产品

3.在做这款产品的时候,遇到的技术难题,以及怎么克服它的

4.KVO和KVC的理解,以及应用场景

KVC,减少

KVO给我们提供了更少的代码,和比NSNotification好处,不需要修改被观察的class, 永远都是观察你的人做事情。 但是KVO也有些毛病, 1. 如果没有observer监听key path, removeObsever:forKeyPath:context: 这个key path, 就会crash, 不像NSNotificationCenter removeObserver。 2. 对代码你很难发现谁监听你的property的改动,查找起来比较麻烦。 3. 对于一个复杂和相关性很高的class,最好还是不要用KVO, 就用delegate 或者 notification的方式比较简洁。

5.nsnotification的使用场景,以及他比delegate 和block的优势

6.做过哪些性能优化

入门级:

用ARC管理内存 在正确的地方使用reuseIdentifier 尽可能使Views透明 避免庞大的XIB 不要block主线程 在Image Views中调整图片大小 选择正确的Collection 打开gzip压缩

中级(这些是你可能在一些相对复杂情况下可能用到的):

重用和延迟加载Views Cache, Cache, 还是Cache! 权衡渲染方法 处理内存警告 重用大开销的对象 使用Sprite Sheets 避免反复处理数据 选择正确的数据格式 正确地设定Background Images 减少使用Web特性 设定Shadow Path 优化你的Table View 选择正确的数据存储选项

进阶级(这些建议只应该在你确信他们可以解决问题和得心应手的情况下采用):

加速启动时间 使用Autorelease Pool 选择是否缓存图片 尽量避免日期格式转换

7.手机卡顿的话会从哪些方面去考虑

在 VSync (当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vertical synchronization),简称 VSync)信号到来后,系统图形服务会通过 CADisplayLink 等机制通知 App,App 主线程开始在 CPU 中计算显示内容,影响因素: 1.对象创建;

2.对象调整;

3.对象销毁;

4.布局计算;

5.Autolayout;

6.文本计算;

7.文本渲染;

8.图片的解码;

9.图像的绘制.

随后 CPU 会将计算好的内容提交到 GPU 去,由 GPU进行变换、合成、渲染。随后 GPU 会把渲染结果提交到帧缓冲区去,等待下一次 VSync 信号到来时显示到屏幕上。由于垂直同步的机制,如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。

CPU性能

GPU性能

________________________________________________我是分割线________________________

自我介绍:

面试官,您好!我叫吴娟,2015年硕士毕业进入目前的公司之后,开始从事iOS开发,到现在有两年半的时间。期间经历过两个项目:云校园和英语爱听说。第一个项目是一个家校互通的在线教育平台,这个平台采用MVVM模式,通过ReactiveCocoa实现,网络数据传输
是采用HTTP协议以及Thrift协议的二进制数据编码实现的。逐渐发展成为了hybird App,将可运营的内容做成H5,随时更替。第二个项目是一个英语听说训练的平台,参与了项目的立项,日常开发,前期也负责跟进APP端研发进度、撰写APP端周报等工作。通过这两个项目的历练,我拥有扎实的Objective-C语言基础,熟悉MVC/Single/KVO/KVC等设计模式,熟练使用storyboard进行UI定制,熟练掌握iOS应用开发、发布、上线流程,对底层也有一定的了解。我在工作当中,有较强的责任心,沟通能力好,与团队相处融洽。希望自己能够每天进步一点点,谢谢~

iOS基础:

一.OC 的语言特性

a. 动态类型:程序直到执行时才能确定所属的类。
运行时再决定对象的类型。简单说就是id类型,任何对象都可以被id指针所指,只有在运行时才能决定是什么类型。像内置的明确的基本类型都属于静态类型(int、NSString等)。静态类型在编 译的时候就能被识别出来。所以,若程序发生了类型不对应,编译器就会发出警告。而动态类型就编译器编译的时候是不能被识别的,要等到运行时(run time),即程序运行的时候才会根据语境来识别。所以这里面就有两个概念要分清:编译时跟运行时。

b. 动态绑定::程序直到执行时才能确定实际要调用的方法
基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。比如我们一般向一个NSObject对象发送-respondsToSelector:或者 -instancesRespondToSelector:等来确定对象是否可以对某个SEL做出响应,而在OC消息转发机制被触发之前,对应的类 的+resolveClassMethod:和+resolveInstanceMethod:将会被调用,在此时有机会动态地向类或者实例添加新的方 法,也即类的实现是可以动态绑定的;isKindOfClass也是一样的道理。

c. 动态加载:
所谓动态加载就是我们做开发的时候,icon图片在Retina设备上要多添加一个张@2x的图片,当设备更换的时候,图片也会自动的替换。

else:
a.多态的出现时为了让不同的类能使用同名的方法。这个让程序的可读性大大提高,也降低了编程难度。
b.动态类型与动态绑定是为了解决随多态的便利而引起的弊端,有了动态类型与动态绑定,不用去考虑输出中的方法是哪个类型的方法,会自动判定。
c.而id类型的出现就是为了更好的承接动态类型与动态方法出来的返回值。

instancetype和id的相同点和不同的:
相同:都可以作为方法的返回类型
不同:1. instancetype可以返回和方法所在类相同类型的对象,id只能返回位置类型的对象 2. instancetype只能作为返回值,id还可以作为参数

你认为OC最大的优点和最大的不足是什么?
最大的优点:运行时的特性
优点:分类(给类扩展方法)、动态识别(isKindOfClass)、
最大的不足:没有命名空间
缺点:不支持多继承(用实现protocol来代替)、不支持运算符重载、 使用动态运行时类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到。(如内联函数等),性能低劣、不支持跨平台。

分类:不改变原有类的基础上,为类增加一些方法
1)分类只能增加方法,不能增加成员变量;
2)在分类方法中可以访问原来类中的成员变量;
3)分类中可以重写原来方法中的实现,但是会覆盖原来的方法,导致原来的方法不可用;
4)分类调用的优先级:分类>原来的类>父类。若包含多个分类,则最后编译的分类优先。

那么self = [super init]到底做了什么呢,又有什么作用?

在解释之前,先回忆一些必要的知识。

1、关于继承
  因为类是有继承特性的,把公共的方法和实例变量写在父类里,子类只需要写自己独有的实例变量和方法即可。
  继承的内容是:所有的实例变量和方法。而且,子类不满意父类方法的话,可以重写。
  继承有单向性,传递性,唯一性。

2、了解super和self的意义。
  super是编译器指令,并非对象。作用:给super发消息,可以执行父类该方法的实现。
  self是系统关键字。self在方法中指代当前方法的调用者。
  self在实例方法中,指代调用当前方法的对象。
  self在类方法中,指代当前类。

在理解这个问题前需要的知识储备都介绍完了。
  首先,因为类是有父类的,而子类定义了除父类中公共实例变量之外的实例变量。所以,在自身的初始化方法中,优先向super发送init消息[super init],初始化父类中公共变量。
其次父类再给父类的父类发送[super init],直到根类NSObject。初始化成功后,再初始化自身特有的变量,从而实现全部变量的初始化。
  最后返回self(初始化完成的对象)。

1.属性:描述类的特征。包括:带下划线的成员变量、getter、setter方法

属性关键字:readwrite 读写、readonly 只可读、assign 直接赋值 引用计数不加1(用于对基本数据类型进行赋值操作,不更改引用计数。也可以用来修饰对象,但是,被assign修饰的对象在释放后,指针的地址还是存在的,也就是说指针并没有被置为nil,成为野指针。如果后续在分配对象到堆上的某块内存时,正好分到这块地址,程序就会crash。之所以可以修饰基本数据类型,因为基本数据类型一般分配在栈上,栈的内存会由系统自动处理,不会造成野指针。)、retain 引用计数加1、copy 新建一个对象,引用计数为1、strong ARC使用,同retain 、weak ARC使用 同assign 可把对应的指针变量置为nil、nonatomic 非原子性访问,有利于多线程、atomic原子性访问

weak 与assign的不同:weak 的对象 遭到摧毁时,系统将这个对象的指针指向nil, OC 给nil发消息是不会有问题的。assign 的对象 遭到摧毁时,对象的指针还指向原来的位置,由于对象被销毁了,容易产生野指针。

为什么IBOutlet修饰的UIView也适用weak关键字?

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

@property :编译阶段由编译器自动帮我们生成ivar成员变量getter方法,setter方法。
@synthesize:如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法
@dynamic:告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)

auto synthesize:自动合成, 每次增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在 prop_list 中增加一个属性的描述,计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现。在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转。

self.:实际上是用了get和set方法间接调用
_:下划线方法是直接对变量操作

使用self.xxx可以兼容懒加载,同时也避免了使用下滑线的时候忽略了self这个指针,后者容易在BLock中造成循环引用。同时,使用 _是获取不到父类的属性,因为它只是对局部变量的访问。

1.self.是对属性的访问,使用它的时候编译器会判断是否为空,为空的话自动实例化。会自动访问get和set方法
2.
是对实例变量的访问,我们没有实例化它,不能使用
3.对类里局部变量访问使用_,外部变量则用self.
4.在getter方法中,不要再使用self。否则会重复调用getter方法,造成死循环

iOS懒加载:
也被成为延迟加载,可以做到用到时再加载
加载过了就不会再次加载,节约了系统资源
对于实际开发中可能会遇到的一些顺序问题,懒加载也能很好的解决

懒加载的实现思路:
1.在类扩展中创建一个属性
2.重写这个属性对应的getter,将要实现的逻辑放到这个getter中
3.考虑到懒加载只加载一次,那么在实现逻辑之前应该判断一下这个属性是否为空,为空才执行逻辑,否则直接返回这个属性

类方法和实例方法:
+:类方法,可以通过类名直接调用,不需要创建一个类的实例。alloc是类方法
-:实例方法,在类的具体实例范围内执行,在调用这个方法之前必须创建一个类的实例。init是实例方法,被alloc方法返回的对象实例调用。

类方法不能访问实例变量,对象方法可以访问实例变量
类方法只能有有类来调用,对象方法只能用对象来调用

2.深拷贝、浅拷贝、完全拷贝:

copy:copy拷贝出来的对象类型,总是不可变对象类型(NSString,NSArray,NSDictionary)
mutableCopy:mutableCopy拷贝出来的对象类型,总是可变对象类型(NSMutableString,NSMutableArray,NSMutableDictionary)

在非集合对象中:
对不可变对象 进行 copy都是指针复制(浅拷贝),进行mutableCopy操作都是内容复制(深拷贝);对可变对象 进行copy 和 mutableCopy操作都是 内容复制

在结合对象中:
对不可变对象 进行 copy都是指针复制(浅拷贝),进行mutableCopy操作都是内容复制(深拷贝);对可变对象 进行copy 和 mutableCopy操作都是 内容复制。集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制

property中的copy属性:
a.因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
b.如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性

@property (nonatomic ,strong) NSArray *array;
NSArray *array = @[ @1, @2, @3, @4 ];
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
self.array = mutableArray;
[mutableArray removeAllObjects];
po self.array
<__NSArrayM 0x60800025a9d0>(
)
3.#import :Objective-C导入头文件的关键字

#include:C/C++导入头文件的关键字。
使用#import头文件会自动只导入一次,不会重复导入,相当于#include和#pragma once;
@class:告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含问题;
#import<>用来包含系统的头文件、导入封装库文件文件(般SDK库)
#import“”:导入自定义的类

a.. 如果不是c/c++,尽量用#import。
b. 能在实现文件中#import,就不在头文件中#import。
c. 能在头文件中@class+实现文件中#import,就不在头文件中#import。

1). import会包含这个类的所有信息,包括实体变量和方法(.h文件中),而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,后面会再告诉你。
2). 在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
备注:#import 就是把被引用类的头文件走一遍,即把.h文件里的变量和方法包含进来一次,且仅一次,而@class不用,所以后者编译效率更高。
3). 在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
4). 如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。

备注:实践证明,A,B相互#import不会出现编译错误。因为<标记>处已经说明#import时文件只被导入一次,所以此条不成立。

iOS 沙盒:sandbox。原理是通过重定向技术,把程序生成和修改的文件定向到自身文件夹中。在沙盒机制下,每个程序之间的文件夹不能互相访问。iOS系统为了保证系统安全,采用了这种机制。
iOS 应用程序在安装时,会创建属于自己的沙盒文件,应用程序不能直接访问其他应用程序的沙盒文件,当应用程序需要向外部请求或接收数据时,都需要经过权限认证,否则,无法获取到数据。
应用程序中所有的非代码文件都保存在沙盒中,比如图片、声音、属性列表,sqlite数据库和文本文件等。
获取沙盒路径:NSHomeDirectory()
沙盒文件组成:
Documents,中一般保存应用程序本身产生文件数据,例如游戏进度,绘图软件的绘图等, iTunes备份和恢复的时候,会包括此目录。注意:在此目录下不要保存从网络上下载的文件,否则app无法上架!
Library:Caches ,此目录用来保存应用程序运行时生成的需要持久化的数据,这些数据一般存储体积比较大,又不是十分重要,比如网络请求数据等。这些数据需要用户负责删除。iTunes同步设备时不会备份该目录。 Preferences,此目录保存应用程序的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录。在Preferences/下不能直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.
tmp:此目录保存应用程序运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录

NSBundle
NSBundle是一个目录,其中包含了程序会使用到的资源,相当于项目中的主目录文件夹,NSBundle用得最多的是获取Plist文件,并获取Plist的内容,Plist文件可以简单理解为小数据库类型的文件,它在项目初始化时默认会创建一个info.plist文件,里面会存储系统的默认配置信息


2018-03-22_第1张图片
image.png
4.MVC 、MVVM、通知、代理、KVO、KVC、单例

MVC:逻辑、视图、数据进行分层,实现解耦。
Model持有数据,View显示与用户交互的界面,而ViewController调解Model和View之间的交互
厚重的ViewController
遗失的网络逻辑(无立足之地)
较差的可测试性

MVVM:由视图(View)、视图模型(ViewModel)、模型(Model)。比MVC更加释放控制器臃肿,将一部分逻辑(耗时,公共方法,网络请求等)和数据的处理等操作从控制器里面搬运到ViewModel中

通知:NSNotification是ios一个调度消息通知的类,广泛用于传值和回调。NSNotificationCenter:通知中心。创建通知、发送通知、接受通知、处理通知、移除通知。

代理delegate:委托别人去做一些事情,比如逆向传值。protocol:ios不支持多继承,所以很多需要用到协议,protocol定义一套公用接口,需要代理类去实现它。
代理的delegate和dataSource有什么区别?block和代理的区别?
delegate:传递的是事件(even),代理可以让A对象通知B对象,我(A)发生的变化,前提B遵循了A的代理,并且实现了A的代理方法。didSelectRowAtIndexPath
dataSource: 传递的是数据。如果A对象声明了数据源,当我们创建A对象的时候,我们就该实现数据源,来告诉A,他所需要的一些数据。 cellForRowAtIndexPath

Block:一个OC 对象,带自动变量的匿名函数。https://www.jianshu.com/p/ee9756f3d5f6#

首先全局变量和静态全局变量的值增加,以及它们被Block捕获进去,这一点很好理解,因为是全局的,作用域很广,所以Block捕获了它们进去之后,在Block里面进行++操作,Block结束之后,它们的值依旧可以得以保存下来。

自动变量是以值传递方式传递到Block的构造函数里面去的。Block只捕获Block中会用到的变量。由于只捕获了自动变量的值,并非内存地址,所以Block内部不能改变自动变量的值。Block捕获的外部变量可以改变值的是静态变量,静态全局变量,全局变量

block里面如何防止retain cycle:
使用弱引用打断block里面的retain cycle
MRC中,_block不会引起retain,ARC中会引起,要用_weak.

KVC:key-value-coding。设置或者改变对象的属性

KVO:key-value-Observe。监控属性的变化,从而做出反应

单例:保证一个类只有一个实例,并且提供一个全局的访问入口访问这个实例。在实际应用中,如果建模的是,确实这个东西只需要一个对象,就用单例模式。在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),一般用于工具类。例如:登陆控制器,网络数据请求,音乐播放器等一个工程需要使用多次的控制器或方法。more:http://www.cocoachina.com/ios/20171123/21300.html

KVO内部实现原理?https://www.jianshu.com/p/e59bb8f59302
Apple 使用了 isa 混写(isa-swizzling)来实现 KVO 。当观察对象A时,KVO机制动态创建一个新的名为:NSKVONotifying_A 的新类,该类继承自对象A的本类,且 KVO 为 NSKVONotifying_A 重写观察属性的 setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。

通知、代理、KVO的区别?

http://blog.csdn.net/dqjyong/article/details/7685933

相同点:传值,不需要耦合
代理:一对一的传值 ,weak
通知:一对多的传值

信号和通知
通知是全局的,不好控制制影响范围
信号需要订阅才生效,取消订阅就失效了

通知的名字是字符串,容易出现不对应的情况
订阅的方式写起来麻烦

block:用copy,block属性为什么需要用copy来修饰?

因为在MRC下,block在创建的时候,它的内存是分配在栈(stack)上的,而不是在堆(heap)上,可能被随时回收。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。通过copy可以把block拷贝(copy)到堆,保证block的声明域外使用。在ARC下写不写都行,编译器会自动对block进行copy操作。

.a 和.framework
静态库:.a和.framework
动态库:.tbd和.framework
静态库和动态库的区别

.a文件肯定是静态库,. tbd肯定是动态库,.framework可能是静态库也可能是动态库
静态库在链接时,会被完整的复制到可执行文件中,如果多个App都使用了同一个静态库,那么每个App都会拷贝一份,缺点是浪费内存。类似于定义一个基本变量,使用该基本变量是是新复制了一份数据,而不是原来定义的;
动态库不会复制,只有一份,程序运行时动态加载到内存中,系统只会加载一次,多个程序共用一份,节约了内存。类似于使用变量的内存地址一样,使用的是同一个变量;
但是项目中如果使用了自己定义的动态库,苹果是不允许上架的,在iOS8.0以后苹果开放了动态加载. tbd的接口,用于挂载. tbd动态库

使用静态库的好处?
模块化,分工合作
避免少量改动经常导致大量的重复编译连接
也可以重用,注意不是共享使用

使用动态库的好处?
使用动态库,可以将最终可执行文件体积缩小
使用动态库,多个应用程序共享内存中得同一份库文件,节省资源
使用动态库,可以不重新编译连接可执行程序的前提下,更新动态库文件达到更新应用程序的目的。

静态库的使用场景?
保护自己的核心代码,自己不想别人看到的部分
将MRC的项目打包成静态库,可以在ARC下直接使用,不需要在转换

5、内存管理:ARC、MRC、内存池

堆:
栈:

自动释放池:autorelease pool是OC的一种内存自动回收机制,延迟释放的特性 。
当你向一个对象发送一个autorelease消息的时候,cocoa就会将对象的一个引用放入 到最新的自动释放池中(当前线程栈顶位置),它任然是一个正当的对象,因此自动释放池定义的作用域内的其他对象都可以向他发送消息.
自动释放池以栈的形式实现.当自动释放池被回收时,他们就从栈中被删除,并且会给池子里面的所有对象都会做一次release操作。

OC的对象存储在堆区

a.引用计算器:既retainCount,每个OC对象内部都有1个8字节空间用来存储retainCount,表示有多少”人”正在使用;
对象刚被创建时,默认计数值就为1,当计数值为0时,系统会自动调用dealloc方法将对象销毁
引用计数器的用法:给对象发送相应的技术操作来改变计数器的值
retain消息:使计数器+1
release消息:使计数器-1
retainCount消息:得到当前当前retainCount的值
b.野指针: 不是NULL指针,是指向"垃圾"内存(不可用内存)的指针(当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址);空指针:没有初始化的指针变量
c.僵尸对象:指一个对象已经被回收,但其数据还存在内存中
僵尸对象有可能可以访问,也有可能不能访问,取决于所占用空间是否已被重新分配.然而,对象一旦被回收就不该再被访问,此时可以开启僵尸对象检测,这样系统会自动检查是否为僵尸对象,但同时也会降低执行效率.
d.内存泄露:指对象没有在该回收的时候被回收,而是一直驻留在内存中,直到程序结束的时候才被释放

MRC:手动管理内存,谁创建,谁销毁
ARC :编译器会自动的在合适的地方插入retain、release、autorelase代码;编译器自动为对象做引用计数. 而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用了ARC).
->强指针与弱指针:
强指针:默认情况下,我们声明的指针都为强指针,也可以使用__strong来显示的声明指针为强指针.
弱指针:使用__weak关键字修饰的指针,例如 __weak Person *p;
作用与区别:在ARC模式下,强指针与弱指针用来作为回收对象的标准,当1个对象即使用弱指针指向,但没有任何强指针指向时就会被立即回收,此时该弱指针会被自动设置为nil.
->ARC模式下的循环引用:
在ARC机制下,如果出现了循环引用,既A对象中有1个属性是B对象. B对象中有1个属性是A对象.此时如果两边都为strong.就会发生内存泄露.
解决方案:1端使用strong 另外1端使用weak

说一下appdelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法

a.应用程序启动,并进行初始化时候调用该方法:aaaplication:didFimnishLanuchingWithOptions:

b.应用进入前台并处于活动状态时候调用:applicationDidBecomeActive:

c.应用从活动状态进入到非活动状态:applicationWillResignActive :

d.应用进入到后台时候调用的方法:applicationDidEnterBackground:

e.应用进入到前台时候调用的方法:appplicationWillEnterForeground:

f.应用被终止的状态:applicationWillTeminate

过程1:没有运行(NOT RUNNING)------->没有激活(INACTIVE);
这个过程会调用aaaplication:didFimnishLanuchingWithOptions:方法,发出UIApplicationDidFinishLaunchingNotification通知;

过程2:没有激活(INACTIVE) ------>激活( ACTIVE)
这个过程会调用applicationDidBecomeActive:方法,发出UIApplicationDidBecomeActiveNOtification通知;

第二种场景:点击Home键---程序挂起或者进入后台;(一种是退到后台,没有退出程序;一种是退到后台,且退出程序)

这里分两种情况:

情况1:点击home键,退到后台挂起(默认情况);注意:挂起状态会占用内存;

2018-03-22_第2张图片
image

情况2:点击home键之后,退到后台,直接终止;

注意:默认的情况下,程序进入后台是不会终止程序的;如果要做到可以退出程序,到plist文件修改一下的值:

找到Application does not run in backgroud设置为yes,在文件中保存的键应该是UIApplicationExitsOnSuspend设置为Yes。

2018-03-22_第3张图片
image

第三种场景:挂起的程序重新运行

注意:application:didFinishLaunchingWithOptions:这个方法只会在程序初始化的时候才会被调用,而且只调用一次;

所以这里不会调用didFinishLaunchingWithOptions这个方法;

2018-03-22_第4张图片
image

简述视图控制器的生命周期。

1)init函数(init;initWithFrame;initWithCoder;等)--初始化
2)awakeFromNib--在loadView之前的工作放在这里
3)viewDidLoad--注意,一个ViewController一个生命周期内这个函数只会调用一次
4)viewWillAppear--view将要出现,每次View消失再出现都会调用
5)viewWillLayoutSubviews--简要对子试图进行布局
6)viewDidLayoutSubivews--完成对子试图布局
7)viewDidAppear--视图将要出现在屏幕上
---上述代码不含部分
8)viewWillDisappear--View将要消失
9)viewDidDisappear--View已经消失

iOS 响应链:http://www.cocoachina.com/ios/20160113/14896.html
在我们点击屏幕的时候,iphone OS获取到了用户进行了“单击”这一行为,操作系统把包含这些点击事件的信息包装成UITouch和UIEvent形式的实例,然后找到当前运行的程序,逐级寻找能够响应这个事件的对象,直到没有响应者响应。这一寻找的过程,被称作事件的响应链

6、Xcode、Instruments、Jenkins、Xcode server、AutoPackageScript

jenkins:
Jenkins等持续集成工具监测到代码变化,自动编译打包,生成开发包,测试直接拿着开发包安装测试即可。步骤
1.拉取远端代码
2.由于某种条件触发后开始自动编译,打包
3.将生成的ipa文件上传到指定位置,供测试下载测试
编译和打包的命令是调用xcodebuild命令
参数 project_name、workspace、CODE_SIGN_IDENTITY、PROVISIONING_PROFILE_SPECIFIER、archive、exportPath

http://www.cocoachina.com/ios/20160418/15936.html
Bot:Xcode server持续集成环境的搭建,Xcode bot的创建,持续集成中证书的配置
设备,
一台Git服务器,可以用GitHub、oschina等。
一台装OS X Server的服务器,必须为MAC,下文简称 Xcode Server服务器。
若干MAC做客户端,下文简称客户端。
若干台iOS测试机。

2018-03-22_第5张图片
1460947852507721.jpg

配置Xcode Server服务器:
下载OS X Server后点击安装;打开 Server 应用,以查看 OS X Server 中提供的服务列表。选择“Xcode”;添加git存储库;
配置Xcode客户端,创建bot
打开xcode>product>create bot;填写bot名称,选择Xcode Server服务器;执行;选择执行条件;Before Integration 在开始持续集成前执行的脚本; After Integration在持续集成后执行的脚本
Xcode Server服务器证书配置
导出的.p12文件;.p12文件导入装OS X Server的MAC的钥匙串中;将Provisioning Profiles拷贝到Xcode Server;在上传代码到仓库时需选择正确的证书
curl

AutoPackageScript
是个脚本

7、.AFNetWorking、SDWebImage、Masonry (mas_makeConstraints)

AFNetWorking:
SDWebImage:
1.提供了一个 UIImageView 的 category 用来加载网络图片并且对网络图片的缓存进行管理
2.采用异步方式来下载网络图片
3.采用异步方式,使用 memory+disk 来缓存网络图片,自动管理缓存。
4.支持 GIF 动画
5.支持 WebP 格式
6.同一个 URL 的网络图片不会被重复下载
7.失效的 URL 不会被无限重试
8.耗时操作都在子线程,确保不会阻塞主线程
9.使用 GCD 和 ARC
10.支持 Arm64

网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题?
答案:利用字典图片地址为key,下载操作为value

iOS缓存:http://www.cnblogs.com/wendingding/p/3950198.html

https://www.cnblogs.com/Jenaral/p/5443842.html
ScaleToFill,它是将图片的宽高强行变成和UIImageView视图的宽高相等来显示,因此该变化无法保证是等比缩放
AspectFit,等比缩放。缩放到图片能够在视图size内完整显示(水平垂直方向均居中),且图片的宽度或者高度(至少一个)恰好与视图的宽度或者高度相等
AspectFill,等比例缩放。它将图片缩放到正好铺满整个UIImageView视图显示,且图片的宽度或者高度(至少一个)恰好与视图的宽度或者高度相等

Masonry:
Masonry是一个对系统NSLayoutConstraint进行封装的第三方自动布局框架,采用链式编程的方式提供给开发者API。系统AutoLayout支持的操作,Masonry都支持,相比系统API功能来说,Masonry是有过之而无不及。
在使用Masonry进行约束时,有一些是需要注意的。

在使用Masonry添加约束之前,需要在addSubview之后才能使用,否则会导致崩溃。
在添加约束时初学者经常会出现一些错误,约束出现问题的原因一般就是两种:约束冲突和缺少约束。对于这两种问题,可以通过调试和log排查。
之前使用Interface Builder添加约束,如果约束有错误直接就可以看出来,并且会以红色或者黄色警告体现出来。而Masonry则不会直观的体现出来,而是以运行过程中崩溃或者打印异常log体现,所以这也是手写代码进行AutoLayout的一个缺点。

Masonry一般在哪里使用??

8、.打包流程:证书、脚本

简述应用上架流程:

9、.Crash:Fabric、device-view device log
10、.数据统计:友盟
11、.应用分发:TestFlight、蒲公英、Fir
二、中级:
1.Storyborad &Xib:https://blog.csdn.net/libaineu2004/article/details/45488665

用StoryBoard开发界面有什么弊端?如何避免?

所有的viewController都在同一个storyboard里进行编辑,随着场景的增加,Xcode打开storyboard的速度会越来越慢,所有的viewController会并列在编辑器左侧,不方便编辑。无法单独调整每个场景的生命周期,所有的场景生命周期有storyboard进行控制。一旦加载了一个场景,除非storyboard卸载,否则卸载场景。
使用sb在项目编译的时候,也都会直接加载到内存中,造成内存的浪费。
优:所见即所得、梳理所有Controller的界面调用关系、复用
劣:难以维护;性能瓶颈;错误定位困难;多人开发产生冲突
优化:1.针对流程结构,可以添加一个场景流程文档。
2.纯代码开发
建议:
对于复杂的、动态生成的界面,建议使用手工编写界面。
对于需要统一风格的按钮或UI控件,建议使用手工用代码来构造。方便之后的修改和复用。
对于需要有继承或组合关系的 UIView 类或 UIViewController 类,建议用代码手工编写界面。
对于那些简单的、静态的、非核心功能界面,可以考虑使用 xib 或 storyboard 来完成

IOS有两大自动布局利器:autoresizing 和 autolayout(autolayout是IOS6以后新增)。autoresizing是UIView的属性,一直存在,使用也比较简单,但是没有autolayout那样强大。如果你的界面比较简单,要求的细节没有那么高,那么你完全可以使用autoresizing去进行自动布局。以下会针对autoresizing进行讨论。
autoresizing :https://www.cnblogs.com/GarveyCalvin/p/4165151.html
autoLayout:
storyboard:方便
Masonry:
autoresizingMask

2.Animation:https://www.jianshu.com/p/9fa025c42261

UIView Animation
[UIView animateWithDuration:0.15 animations:^{
self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
}];
Core Animation
帧动画
自定义转场动画

clipsToBounds :是View的属性,如果设置为yes,则不显示超出父View的部分
masksToBounds:是CALayer的属性,如果设置为yes,则不显示超出父View Layer的部分
据说有性能损耗

ios view的layout
layoutSubviews:设置不为CGRectZero 的frame、addSubview、滚动一个UIScrollView会触发layoutSubviews
layoutIfNeeded:如果,有需要刷新的标记,立即调用layoutSubviews进行布局
setNeedsLayout:需要重新布局,不立即刷新
setNeedsDisplay:
drawRect:重绘
sizeThatFits:计算出最优size, 但是不会改变UIView的size https://www.jianshu.com/p/ce26f05cd7cc
sizeToFit:计算出最优size, 并且改变UIView的size

3.Block
4.GCD

进程与线程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调动的
线程是进程的一个实体,是CPU调度和分派的基本单位。线程基本上不拥有系统资源,只拥有一点在运行中必不可少的资源,但是它可与同属一个进程的其他线程共享进程所拥有的全部资源

并行与并发
并行:指两个或者多个事情在同一时刻发生;
并发:指两个或者多个事情在同一时间间隔内发生;

http://www.cocoachina.com/ios/20180313/22573.html
Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法;
关键词:任何和队列
两种执行任务的方式:同步和异步
队列:串行队列(Main Dispatch Queue)和并行队列(Global Dispatch Queue)
使用步骤:
创建队列,将任务添加到任务队列,然后系统就根据系统任务执行
dispatch_once
dispatch_after
dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];
NSData * data = [[NSData alloc]initWithContentsOfURL:url];
UIImage *image = [[UIImage alloc]initWithData:data];
if (data != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
}
});

项目中用到:dispatch_async 转码 下载资源

5.runtime

https://blog.csdn.net/coyote1994/article/details/52441513
runtime是属于OC的底层,是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API,可以进行一些非常底层的操作.

runtime可以用来做什么
a.在程序运行过程中,动态创建一个类(比如KVO的底层实现)
b.在程序运行过程中,动态地为某个类添加属性/方法。可以用于封装框架(想怎么改就怎么改) 这就是我们runtime机制的主要运用方向
c.遍历一个类中所有的成员变量(属性)/所有方法。(比如字典–>模型:利用runtime遍历模型对象的所有属性, 根据属性名从字典中取出对应的值, 设置到模型的属性上;还有归档和接档,利用runtime遍历模型对象的所有属性)

OC程序与运行时系统交互分为三个不同等级:
a.通过OC源代码
b.通过定义在Foudation框架中NSObject中的方法
NSObject方法的一些简单的查询的运行时系统信息。这些方法允许对象自省(自我查找)。这种方法的例子是类方法,例如isKindOfClass:问一个对象来确定它的类:isMemberOfClass测试对象在继承结构中的层次位置,respondsToSelector,这表明一个对象是否能接受特定的消息,conformsToProtocol:确定对象是否实现在特定协议中定义的方法,methodForSelector:提供方法实现的地址。
c.通过对runtime 库函数直接调用
Class PersonClass = object_getClass([Person class]);
Method oriMethod = Method class_getClassMethod(Class cls , SEL name);
Method class_getInstanceMethod(Class cls , SEL name)

SEL:它是selector在 Objc 中的表示
id:是一个参数类型,它是指向某个类的实例的指针
ivar:是表示成员变量的类型
Class:其实是指向 objc_class 结构体的指针

消息传递机制:
objc_msgSend

项目中用到:万能跳转
NSString *clsName = params[@"viewModelClass"];
if (clsName) {Class cls = NSClassFromString(clsName);}

6.runroop

http://www.cocoachina.com/ios/20150601/11970.html
苹果是如何利用 RunLoop 实现自动释放池、延迟回调、触摸事件、屏幕刷新、定时器等功能。

一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出。
RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑

NSRunLoop
CFRunLoopRef
苹果不允许直接创建 RunLoop,它只提供了两个自动获取的函数:CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。

线程和runloop的关系?
线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。


2018-03-22_第6张图片
image

界面更新

当在操作 UI 时,比如改变了 Frame、更新了 UIView/CALayer 的层次时,或者手动调用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,这个 UIView/CALayer 就被标记为待处理,并被提交到一个全局的容器去。

苹果注册了一个 Observer 监听 BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件,回调去执行一个很长的函数:
_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。这个函数里会遍历所有待处理的 UIView/CAlayer 以执行实际的绘制和调整,并更新 UI 界面。

一个 run loop 为 线程监测一个或多个事件源。当事件到达的时候,系统唤醒线程并调度事件到 run loop,然后分配给指定程序。如果没有事件出现和准备处理,run loop 把线程置于休眠状态。

https://blog.csdn.net/fhbystudy/article/details/12856261

7.引用计数:

retainCounter
创建对象 +1 有引用+1
release -1
为0 销毁

8.ReactiveCocoa:http://blog.devtang.com/2016/01/03/reactive-cocoa-discussion/

学习路径:1. FRP 的思想概要 2. RAC 的 operations 介绍 3. 冷信号与热信号解惑 4. 生命周期指南 5. disposable 和多线程 6. 实战分享
应用场景:数据随着时间而产生
a.UI 操作,连续的动作与动画部分,例如某些控件跟随滚动。
b.网络库,因为数据是在一定时间后才返回回来,不是立刻就返回的。
c.刷新的业务逻辑,当触发点是多种的时候,业务往往会变得很复杂,用 delegate、notification、observe 混用,难以统一。这时用 RAC 可以保证上层的高度一致性,从而简化逻辑上分层。只要有通知的业务逻辑,RAC 都方便有效化解。
d.概括的说,应该就是统一所有异步事件吧。
不适用的场景,与时间无关的,需要积极求解的计算,例如视图的单次渲染

RACSubject + RACComand 来简化和统一应用的错误处理逻辑
UI 交互上的点确实好多,比如下拉刷新、上拉导航条变透明
实时响应用户的输入,控制按钮的可用性,这点用 RAC 来实现非常简单。

劣势:调试比较痛苦
调试小技巧:instruments 的两个插件,signalEvents 这个可以看到流动的信号的发出情况,对于时序的问题可以比较好的解决。diposable 可以检查信号的 disposable 是否正常
性能调试,靠Instruments的Time Profile,少用 RACCommand、RACSequence
Bug调试,靠log

可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。可以在水龙头上加一个过滤嘴(filter),不符合的不让通过,也可以加一个改动装置,把球改变成符合自己的需求(map)。也可以把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。

RAC统一了对KVO、UI Event、Network request、Async work的处理,因为它们本质上都是值的变化(Values over time)。

10.数据持久化

1.plist(XML属性列表归档)
2.偏好设置
3.NSKeydeArchiver归档(存储自定义对象)
4.SQLite3(数据库,关系型数据库,不能直接存储对象,要编写一些数据库的语句,将对象拆开存储)
5.Core Data(对象型的数据库,把内部环节屏蔽)

三、高级:
1.优化:

如果APP启动过慢,可能的原因是:

查看:
Pre-main时间,从在屏幕上点击你的app icon开始,到应用执行到main()方法或者执行到,ios10通过Xcode中的Edit Scheme -> Run -> Argument,设置参数DYLD_PRINT_STATISTICS值为1
main 函数加启动时间,didFinishLaunchingWithOptions加结束时间 ->启动时间

App的启动会包括以下几个部分(来自WWDC 2012 Session 235):
1)链接和载入:可以在Time Profile中显示dyld载入库函数,库会被映射到地址空间,同时完成绑定以及静态初始化。
2)UIKit初始化:如果应用的Root View Controller是由XIB实现的,也会在启动时被初始化。
3)应用回调:调用UIApplicationDeleagte的回调:application:didFinishLaunchingWithOptions
4)第一次Core Animation调用:在启动后的方法-[UIApplication _resportAppLaunchFinished]中调用CA::Transaction::commit实现第一帧画面的绘制。
基本上减少启动时间就是在这些方面下一些功夫,如果你的程序启动很慢,能做的首先是将与显示第一屏画面无关的操作放到之后执行;
如果是用XIB文件load第一屏,XIB文件中的View层也要如果扁平,不要有太多图层。

如果APP卡顿,可能的原因是:
https://blog.csdn.net/zhai19931004/article/details/51361830
cell上layer尽量避免使用圆角
优化图片的加载方式

UITableView的重用机制
cell的重用,reuseIdentifier顾名思义是一个复用标识符,是一个自定义的独一无二的字符串,用来唯一地标记某种重复样式的可复用UITableViewCell,系统是通过reuseIdentifier来确定已经创建了的指定样式的cell来进行复用,iOS中表格的cell通过复用来提高加载效率,因为多数情况下表格中的cell样式都是重复的,只是数据模型不同而已,因此系统可以在保证创建足够数量的cell铺满屏幕的前提下,通过保存并重复使用已经创建的cell来提高加载效率和优化内存,避免不停地创建和销毁cell元素。

visibleCells,存放当前显示的的cells,当需要更新显示数据时,dequeueReusableCellWithIdentifier会先在可重用cell队列 reusable-cell queue中返回一个cell对象,若不存在,则返回nil;

2.内存泄漏的处理方式:

a.scheme-NSZombieEnabled
b.Instruments - profile - leaks
c.weak 和 strong是否匹配

3.ios逆向
4.swift
四、其他
1.算法

交换算法:
A= A+B;
B= A-B;
A= A-B。

冒泡算法:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 O(n)

- (NSArray *)bubleSort:(NSArray *)arr{
    NSMutableArray * array = [NSMutableArrayarrayWithArray:arr];
    for (int i =0; i < array.count; i ++) {
        
        
        for (int j = i +1; j < array.count; j ++) {
            if ([array[i]intValue] > [array[j] intValue]) {
                NSString * temp;
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
        NSLog(@"%@", array);
        
    }
    return array;
    
}

快排:快速度排序是经典的divide & conquer (分治算法)
在数组中取得一个值为标兵
对标兵左右区间进行划分,将比标兵大的放到又边,小的放到左边,倒序反之。
重复上过程,到对比结束

-(void)quickExhaut:(NSMutableArray *)dateSource WhithLeft:(NSInteger )left AndRight:(NSInteger)right{
    if (left>=right) {
        return;
    }
    NSInteger i = left;
    NSInteger j = right;
    //标兵值
    NSInteger key = [dateSource [i] integerValue]; 
    //查询
    while (i= key) {
       j--;
    }
        //如果小于标兵就放到前面
        dateSource[i]= dateSource[j] ;
    while (i
2.概念

TCP和UDP:
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证
  
UDP应用场景:
1.面向数据报方式
2.网络数据大多为短消息
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高

HTTP和HTTPS:
http:Hyper Text Transfer Protocol
https:Hyper Text Transfer Protocol Secure

http是HTTP协议运行在TCP之上。所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。

https是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份。

TCP用的port是80
https用的是443

项目:

1.介绍一下项目,然后自己做的部分,找一个亮点说一下如何实现的

云校园的亮点:thrift、可配置化、聊天腾讯IM、资讯
1.统一SDK的接入
2.支线版本的开发与维护
3.接入360摄像头的SDK
4.无登录态的改造
5.私有化,扫描二维码
6.万能界面跳转:根据名字创建对象,利用KVC给对象复赋值

ELLearn的亮点:音频录音、转码、上传、下载、播放、评分(云知声);角色扮演的复杂性
1.注册登录+个人中心模块
AFNetWorking
2.单词跟读和句子跟读也有参与

2.开发中遇到过什么困难是如何解决的

1.证书问题比较繁琐
2.作业详情页面的布局:
a.UITableView实现:进入页面改变导航栏,透明度设置为0,退出页面的时候,导航栏复原,透明度设置为1;滑动的时候,透明度设置为1
发现从这个页面返回到其他页面时,字体怎么设置都变不回去
b.xib实现,自己实现nav+tableView。
用autoresizong,nav 上、左右、中 ,tableView 上、左
代码设置他们的宽和高
self.edgesForExtendedLayout = UIRectEdgeNone;(会使坐标原点在导航栏左下角)
self.tableView.contentInset = UIEdgeInsetsMake(_navView.height, 0, 20, 0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(_navView.height, 0, 0, 0);//scrollIndicatorInsets就是改变Indicator的位置。

关于滚动视图contentSize、contentOffset、contentInset 的整理
contentSize 是scrollview可以滚动的区域,比如frame = (0 ,0 ,320 ,480) contentSize = (320 ,960),代表你的scrollview可以上下滚动,滚动区域为frame大小的两倍。

contentOffset 是scrollview当前显示区域顶点相对于frame顶点的偏移量,比如上个例子你拉到最下面,contentoffset就是(0 ,480),也就是y偏移了480

contentInset 是scrollview的contentview的顶点相对于scrollview的位置,例如你的contentInset = (0 ,100),那么你的contentview就是从scrollview的(0 ,100)开始显示

学习:

1.遇到一个问题完全不能理解的时候,是如何帮助自己理解的?举个例子?

首先会自己去查,从官网查起,因为官网一般都是英文,而且二

问题比较紧急会直接百度或者请教同事,然后自己再去官网等查自己的资料

问题不紧急,先看官网,再看google

2.有看书的习惯么?最近看的一本是什么书?有什么心得?

腾讯传:
浪潮之巅:
腾讯ios测试实践:
项目计划、进度与控制:

3.有没有使用一些笔记软件?会在多平台同步以及多渠道采集么?(如果没有,问一下是如何复习知识的)

以前:印象笔记
现在:有道笔记

4.有没有使用清单类,日历类的软件?(如果没有,问一下是如何安排,计划任务的)

有道+日历:每天列好待做事项、今日需解决、今日未解决等

5.平常看博客么?有没有自己写过?(如果写,有哪些收获?如果没有写,问一下不写的原因)

看一些,唐巧
上有几篇:ios技术框架图、ios证书、ios常见报错

人事问题:

1.为啥离家上一家公司?
这是我进入社会的第一家公司,我非常感谢公司和我们团队的每一个人。从工作上来说,我的iOS技能以及一些为人处世的哲学都是在这里学到的,从生活上来说,我在人生地不熟的深圳,他们成了我的第一批朋友。但是,天下无不散之筵席,现在公司里边iOS就两个人,我觉得我还需要一个更好的学习环境,所以我选择离开。

2.你最大的缺点是什么?
我的缺点是比较执着,比如在技术方面比较爱钻研,有的时候会为一个技术问题加班到深夜。还有就是,工作比较按部就班,总是按照项目经管的要求完成任务。另外的缺点是,总在息的工作范围内有创新意识,并没有扩展给其他同事。这些问题我想我可以进入公司后以最短的时间来解决,我的学习能力很强,我相信可以很快融入公司的企业文化,进入工作状态。我想就这些吧。

喜欢先弄清楚原理,如果一个事情,自己没有理解清楚,做起来心里不踏实。

3.你最大的优点是什么?
做事情之前比较有规划, 喜欢规划好
比如说,我想提升自己了,我会先去搜相关方面的知识,相关当面的书,然后给自己定一个计划,每天看一小时的书,然后再去实践或者怎样。

4.你未来3-5年的职业规划是怎样的?
我从事iOS开发也有两年半了嘛,我打算自己在这方面沉淀一两年时间,能够独当一面。之后的3-5年,期望自己能够做到项目经理的职位。我也打算在对技术沉淀的同时,也多了解产品方面的东西。因为有一颗产品心的程序员才是好的工程师。
5.你对薪资的要求?
我对工资没有硬性要求,我相信贵公司在处理我的问题上会友善合理。
6.什么时候能入职?

  1. 你还有什么问题问我吗?
    谦虚礼貌的问面试官怎么称呼,
    该部门工作中的信息,
    如项目情况,开发技术
    贵公司的晋升机制

办公APP:

手机开门:
蓝牙开门,一对一的连接模式,蓝牙协议多不好适配,配对时间长,连接速度慢
WiFi开门,WiFi,可以连无数台手机,符合你们日常习惯。WIFI技术开门可以适配所有智能手机开门
NFC,NFC比较安全,普及程度最低。
二维码识别开门,

从商业性角度考虑,笔者优先选择app开门(低成本快速获取并粘住用户后,进一步实现商业化运作,最终形成自己的商业生态),其次是微信公众号开门(微信公众号不是自己的平台,流程长,适合访客边缘少量用户,后期想开发其他功能性产品比较难,对一次性访客,微信公众号开门是不错的选择),智能手环开门(适合小区场景的老人和小孩人群不使用手机的用户群体),最后是二维码开门(解决访客便捷性问题,但如果仅仅是为了开门,安全上有一定隐患,且不具有后续商业开发价值)

安全性上来讲,通过app开门安全性最高,二维码最低(二维码可以拍照复制,可重复,无法做到实名)
从便捷性上讲:二维码开门最简单,但是安全系数相对较低。
综合而言:通过微信和钥匙转授权功能来接解决访客功能,即解决了安全性的问题又解决便捷性功能。

手机签到:
WIFI打卡:https://blog.csdn.net/vitamio/article/details/75675589
在iOS端,他们的处理都是根据当前手机连接的wifi信息进行打卡。据iOS同事说,iOS获取周围wifi信息需要申请此功能,并最低支持版本是iOS 9。另外据可靠消息,分享逍客对mac地址的处理也是通过忽略低4位进行匹配。
手机获取的无线路由器MAC地址的低4位是变化的。那我们实现这个需求时,除了匹配虚拟位置、手机信息、wifi相关等其他信息外,只针对mac地址,我们可以忽略mac地址的低4位来做匹配。
GPS打卡:获取GPS定位

1.GPS定位系统,辐射范围仅 300 米,超出范围则无法打卡。
2.设置考勤WIFI,只有链接上规定的考勤WIFI才能打卡。
3.可识别手机型号,规定员工只能用一部手机打卡。
4.拍照上传功能,可将员工所处的地点和时间拍照上传至移动端供主管部门审批。

移动考勤
外勤、多人同时打卡、多地考勤同步、复杂排班设置、移动实时管理、智能报表下载,满足公司不同部门、不同员工的排班管理、会议室管理:

钉钉
钉咚

涉及到的技术
手机定位 :
1.基于GPS的定位方式是利用手机上的GPS定位模块将自己的位置信号发送到定位后台来实现手机定位的。GPS信号穿透力差
2.基站定位则是利用基站对手机的距离的测算距离来确定手机位置的,依赖基站的覆盖
3.利用wifi小范围定位:

ios获取定位:https://blog.csdn.net/sheng_bin/article/details/53353576
GPS:获取定位权限、CoreLocation.framework CLLocationManager
第三方SDK:

ios二维码扫描:
AVCaptureDevice

ios生成二维码:
https://blog.csdn.net/surpassblack/article/details/72821101

https://github.com/ChenYilong/iOSInterviewQuestions

你可能感兴趣的:(2018-03-22)