iOS常见问题


Autolayout和Frame

Autolayout的约束最后都是系统最终转化成frame来进行布局的,对与一个View来说,最终确定其中心点位置和View的宽高。当Autolayout和Frame设置上产生冲突的时候,则会以Autolayout的设置为准。

- (void)setNeedsLayout;

- (void)layoutIfNeeded;

- (void)layoutSubviews;

setNeedsLayout方法标记当前view是需要重新布局的,在下一次runloop中,进行重新布局。如果说想在当前runloop中立刻更新布局,则通过调用layoutIfNeeded方法可以实现,此时系统会调用layoutSubviews。在layoutSubviews方法中,可以自己定义新的view或者改变子view的布局。


App启动过程优化

①解析Info.plist 

加载相关信息,例如闪屏

沙箱建立、权限检查

②Mach-O加载 

如果是胖二进制文件,寻找合适当前CPU架构的部分

加载所有依赖的Mach-O文件(递归调用Mach-O加载的方法)

定位内部、外部指针引用,例如字符串、函数等

执行声明为__attribute__((constructor))的C函数

加载类扩展(Category)中的方法

C++静态对象加载、调用ObjC的 +load 函数

③程序执行 

调用main()

调用UIApplicationMain()

调用applicationWillFinishLaunching

换成另一个说法就是:

App开始启动后,系统首先加载可执行文件(自身App的所有.o文件的集合),然后加载动态链接器dyld,dyld是一个专门用来加载动态链接库的库。 执行从dyld开始,dyld从可执行文件的依赖开始, 递归加载所有的依赖动态链接库。

动态链接库包括:iOS 中用到的所有系统 framework,加载OC runtime方法的libobjc,系统级别的libSystem,例如libdispatch(GCD)和libsystem_blocks (Block)。

https://blog.csdn.net/olsQ93038o99S/article/details/81518485



weak和assign的区别

weak   

只可以修饰对象。

weak 不会产生野指针问题,因为weak修饰的对象释放后(引用计数器值为0)自动被置为nil,之后再向该对象发送消息也不会崩溃。

assign 

可以修饰对象和基本数据类型。

如果修饰对象,会产生野指针问题;如果修饰基本数据类型则是安全的。修饰的对象释放后,指针不会被自动置空,此时向对象发送消息会崩溃。

assig适用于基本数据类型int    float  struct等类型,会被放入栈中,先进后出。

weak适用适用于 delegate ,不会导致野指针,也不会造成循环引用


iOS响应链和事件传递

UIResponder 响应者对象。只有继承UIResponder的类,才能处理事件。

UIApplication,UIView,UIViewController都是继承自UIResponder类,可以响应和处理事件。CALayer不是UIResponder的子类,无法处理事件。

事件的分发和传递

1.当iOS程序中发生触摸事件后,系统会将事件加入到UIApplication管理的任务队列中

2.UIApplication将处于任务队列最前端的事件向下分发,即UIWindow。

3.UIWindow将事件向下分发,即UIView。

4.UIView首先看自己是否能处理事件,触摸点是否在自己身上。如果能,则继续寻找子视图。

5.遍历子空间,重复以上两步。

6.如果没有找到,那么自己就是事件的处理者。

7.如果自己不能处理,那么不做任何处理。

其中UIView不接受事件处理的情况有:

1)alpha <0.01                 2)userInteractionEnabled = NO        3)hidden = YES

怎样寻找最合适的View

// 此方法返回的View是本次点击事件需要的最佳

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event

// 判断触摸点是否在视图内

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event

使用场景:

1、扩大按钮的点击范围

UIButton重写     - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event    方法

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {

    CGRect bounds = self.bounds;

    bounds = CGRectInset(bounds, -10, -10);

  // CGRectContainsPoint  判断点是否在矩形内

    return CGRectContainsPoint(bounds, point);

}

2.不规则按钮的点击区域

// // 改变图片的点击范围

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {

    // 控件范围宽度多40,高度20

    CGRect bounds = CGRectInset(self.bounds, -20, -20);

    NSLog(@"point = %@",NSStringFromCGPoint(point));

    UIBezierPath *path1 = [UIBezierPath bezierPathWithRect:CGRectMake(-20, 0, 40, 120)];

    UIBezierPath *path2 = [UIBezierPath bezierPathWithRect:CGRectMake(self.frame.size.width - 20, 0, 40, 120)];

    if (([path1 containsPoint:point] || [path2 containsPoint:point])&& CGRectContainsPoint(bounds, point)){

        //如果在path区域内,返回YES

        return YES;

    }

    return NO;

}



Http 和 Https    的区别

HTTPS 是以安全为目标的HTTP通道,在HTTP的基础上加入了SSL层。

HTTPS协议的主要作用是:1.建立一个信息安全通道,来保证数据传输的安全;2、确认网址的真实性。

主要区别:

1.HTTPS协议需要到 ca 申请证书,并需要一定的费用;

 2.http是超文本呢传输协议,信息是明文传输, https则是具有安全性的ssl加密传输协议;

3.http用的端口是80  https用的端口是443;

4.http连接是简单,无状态的, https协议是由SSL+HTTP协议构成的可进行加密传输、身份认证的网络协议;

HTTPS的工作原理:

说明:非对称加密算法RSA 是内容加密的一种算法,它有两个秘钥:公钥和私钥。公钥是公开的钥匙,所有人都可以知道;私钥是私密的,只有持有者知道。通过公钥加密的内容,只能通过私钥解密。非对称加密算法的安全性很高,但是计算量庞大,比较消耗性能。

1)客户端发起 https 请求 

     客户端连接到服务器端的443端口上,客户端会发送一个密文族给服务端;

2)服务端配置公钥和私钥,并传输证书(公钥)

       服务端配置一套证书,包含公钥和私钥,传输的公钥中包含很多信息,如证书的颁发机构、过期时间等等;

3)客户端解析证书,并传送加密信息

    客户端的TLS,验证公式的相关信息,如果没有问题,生成随机数,并使用该证书对该随机值进行加密,目的是让服务端得到这个随机值;

4)服务端利用私钥解密信息

    服务端利用私钥解密,得到随机数,完成非对称加密的过程,实现了身份认证和密钥协商。然后把该内容通过该值进行对称加密;

5)传输加密后的信息,客户端解密信息

    服务端用随机值加密后的信息,可以在客户端用公钥被还原。



TCP和UDP

TCP     可靠、稳定,面向连接。会有三次握手来建立连接

UDP    快。无状态的传输协议。 适用于一次只传送少量数据、对可靠性不高的应用场景。



UIViewController的生命周期

详细地址:https://blog.csdn.net/abap_brave/article/details/80148781

1.init 里不要出现创建view的代码。都是关键数据的初始化;

2.loadView 初始化关键点额View,加载视图

    awakeFromNib:    从xib或storyboard中加载UIViewController将要被激活时调用

3.ViewDidLoad  

4.viewWillAppear                     视图即将显示时调用

5.viewWillLayoutSubviews:     视图将要布局其子视图时被调用

    viewDidLaySubviews:          视图布局完成其子视图时被调用

6.viewDidAppear

7.viewWillDisppear

8.viewDidDisapper

9.dealloc   被释放

其他

viewWillUnload 内存警告,释放    view

viewDidUnload 内存警告,释放    view



GET和POST

get 方式,APP会把http header 和 data 一并发送出去,服务器返回 200;

post 方式, 浏览器先发送header, 服务器相应 100 continue ,浏览器再发送 data,服务器响应 200 ;


GET 请求有长度显示1024, POST没有长度限制;

GET参数通过URL传递, POST放在Request Body 中;

GET在浏览器中可以回退,POST会重新进行请求



深拷贝和浅拷贝

浅拷贝:对内存地址的复制                深拷贝:拷贝对象的具体内容

是否开启新的内存地址 、 是否影响内存地址的引用计数

不可变类型(NSString,NSArray,NSDictionary)         copy都是浅拷贝

                                                                                mutableCopy都是深拷贝

可变类型(NSMutableString,NSMutableArray)         copy都是深拷贝

                                                                                mutableCopy都是深拷贝


设计模式

1.MVC 模式

2.MVVM模式

    由MVP发展过来的,Model - View - ViewModel ,即 模式——视图——视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。

    在MVVM的框架下视图和模型是不能直接通信的,之间通过ViewModel来进行通信,ViewModel通常要实现一个observer观察者,当数据发生变化,viewModel能监听到数据的变化,然后通知到对应的视图做自动更新,当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。

3.单例模式  

    确认一个类全局只创建一次,只有一份实例,用户进行资源共享控制

4.代理模式

    当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。

5.观察者模式KVO

    察者模式本质上时一种发布-订阅模型,用以消除具有不同行为的对象之间的耦合,通过这一模式,不同对象可以协同工作,同时它们也可以被复用于其他地方Observer从Subject订阅通知,ConcreteObserver实现重现ObServer并将其重载其update方法。    

6.工厂模式



KVC 和KVO 

KVC  key-value-coding 键值编码。

可以允许开发者通过key 直接访问对象的属性,或者给对象的属性赋值,而不需要调用明确的存取方法,利用 runtime 运行时动态的访问和修改对象的属性。

KVO  key-value-Observer 观察者模式     

步骤:

1.当类A的对象第一次被观察的时候,系统会在运行期动态创建原类的派生类,

2.在派生类中重写原类中被观察属性的 setter 方法,派生类在被重写的setter方法中实现通知机制

3.派生重写class方法,将自己伪装成原类,派生类还会重写dealloc方法释放资源

4.系统会将所有指向原类对象的isa指针指向派生类的对象


Delegate ,通知 和 Block 的使用场景

delegate

控制器的反向传值 或者 传递 一个事件。

block

写法简练,

1、使用block需要注意防止循环应用,使用weakSelf,     

2、Block类型属性使用 copy 修饰     

3、block 在堆中,想改变block 里面变量的值,需要加参数 __block

Notification通知

一对多, 需要先注册通知,发送通知,处理通知



OC 的内存管理

https://www.cnblogs.com/wendingding/p/3704739.html

1、谁创建,谁释放: (1)如果你使用alloc,new , copy 来创建了一个对象,那么必须调用release 或者 autorelease 方法 (2)不是你创建的对象就不用你去负责   

2、谁ratain ,谁release 

3、dealloc 方法前面,一定要写明 【super dealloc】

4、@property 默认生成setter 和 getter 方法,

5、autorelease 会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子中所有的对象做一次release 。



排序方法

1.快排排序

通过一趟排序将要排序的数据分割成两部分,其中一部分的所有数据比另一部分的所有数据都要小,然后按此方法对这两部分数据分别进行快速排序,整个过程可以递归进行,以达到整个数据变成有序序列。

2.冒泡排序



懒加载

用到时再记载,而且只加载一次

本质上是: 重写 get 方法时,先判断对象当前是否为空,为空的话再去实例化对象.

好处:1、代码可读性强,不必将所有代码都写到viewDidLoad  2、每个控件分别负责格子的getter方法  3、对系统的内存占用率减小



属性关键字 atomic、nonatomic、readonly、readwrite、assign、retain、copy

1.readwrite  可读可写特性,需要生成 getter 和 setter 方法;

2.readonly    只读特性.只会生成 getter 方法,不会生成 setter 方法,不希望在类外部改变属性;

3.assign 赋值特性.assign用于基本数据类型. 当修饰的对象释放后,指针不会被自动置空,此时向对象发送信息会崩溃.

4.retain 

5.copy 拷贝特性. 修饰可变类型是深拷贝, 修饰不可变类型是浅拷贝.   常用语block

6.nonatomic非原子操作。


Runtime

运行时机制。

OC在三种层面上与 Runtime 系统进行交互:

    1.通过 OC 源代码


    2.通过 Foundation框架的 NSObject 类定义的方法

        (1)    -isKindOfClass: 和 -isMemberOfClass: 方法检查对象是否存在于指定的类的继承体系中(是否是其子类或者父类或者当前类的成员变量);

        (2)    -respondsToSelector: 检查对象能否响应指定的消息;

        (3)    -methodForSelector: 返回指定方法实现的地址。

    3.通过对Runtime库函数的直接调用

          (1)Swizzling  

+ (void)load {   

[super load];   

Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:));   

Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(swizzling_ObjectAtIndex:));    method_exchangeImplementations(fromMethod, toMethod);}

         (2)    NScoding 通过objv_ivar_list 获取成员列表,进行归档;


其他

objc_class 在运行时中关联了 objc_ivar_list (成员列表)    objc_method_list (方法列表)

IMP(指针,指向方法的实现地址)


RunLoop 和线程的关系

1    每条线程都有唯一的一个RunLoop对象与之对应;

2    主线程的 Runloop 是自动创建并启动;

3    子线程的 Runloop 需要手动开启;

4    RunLoop是用来管理线程的,当线程的Runloop 被开启后,线程会在执行完任务之后进入休眠状态,有任务后就会被唤醒去执行任务;

CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。


RunLoop 的几种模式

Runloop一共5种模式。

1.NSDefaultRunLoopMode //默认的

2.UITrackingRunLoopMode //UI模式(苹果为了用户体验,所以这个优先级较高),比如当滑动UIScrollView的时候,runloop会切到这个模式下,当滑动事件结束时,runloop会切到NSDefaultRunLoopMode

3.NSRunLoopCommonModes 占位模式,相当于 NSDefaultRunLoopMode + UITrackingRunLoopMode 



描述 iOS 程序的运行流程

https://www.jianshu.com/p/a0b9ce0497f9

1    main函数执行前:加载dylb 、初始化依赖库、初始化 runtime 、回调runtime

2    main 函数执行后: 调用UIApplicationMain函数, 开启主线程runloop监听系统事件  , 通知Appdelegate  , 设置 rootViewController , 调用 self.window makeKeyAndVisable显示窗口



堆和栈的区别

栈区: 由编译器自动分配释放,速度很快    在内存中是连续的区域

堆去:由程序员分配释放,速度较慢         在内存中不连续,通过指针连接起来

全局去(静态区):存放全局变量和静态变量,结束后由系统释放。

文字常量区

程序代码区


多线程

NSThread 

NSOperation

GCD (重点)


Block

block本质是异步执行的代码块。block作为对象的属性,使用copy 从栈区拷贝到堆去,拥有该block的所有权,避免提前释放。

使用方法:1. 声明 block     2.定义类的 Block 属性     3.实现block  4.赋值调用 block方法



AFNetworking 底层原理分析

1    NSURLSession:网络通信模块(核心模块) 对应 AFNetworking中的AFURLSessionManager和对HTTP协议进行特化处理的AFHTTPSessionManager,AFHTTPSessionManager是继承于AFURLSessionmanager的

2    Security:网络通讯安全策略模块 对应 AFSecurityPolicy

3    Reachability:网络状态监听模块 对应AFNetworkReachabilityManager

4    Seriaalization:网络通信信息序列化、反序列化模块 对应 AFURLResponseSerialization

5    UIKit:对于IOSUIKit的扩展库



SDWebImageView 原理




苹果内购流程

1、遵循苹果内购协议,填写银行卡和公司信息

2、创建项目的内购条目

3、添加沙盒测试账号

4、进入支付界面,调用内购

    1)从后台获取最新的商品信息列表;

    2)创建订单,后台返回订单号;

    3)APP向苹果发送购买请求,返回支付结果

    4)监听购买结果

    5)交易结束后,APP从沙盒中获取购买凭据,发送给后台,后台去app store上验证支付信息,返回APP最终的支付结果,刷新道具最新数据;






C , C++, OC 混用

.m 可以识别   C 和 OC;

.mm 可以识别 C  C++  和 OC;

.cpp 只能识别 C 和 C++



Runtime 的消息转发机制

objc_msgSend(structobjc_super *_Nonnullsuper,SEL_Nonnullop, ...)

https://ke.qq.com/course/356310

1.动态方法解析 (resolveInstanceMethod)

2.快速转发   (forwardTargetForSelector) 

3.慢速转发    

    - methodSignatureForSelector 

    - forwardInvocation 

4.避免崩溃的方法 - (void)doesNotRecognizeSelector:(SEL)aSelector 

你可能感兴趣的:(iOS常见问题)