美文网首页
iOS常见问题

iOS常见问题

作者: anpt | 来源:发表于2019-04-16 18:15 被阅读0次


    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常见问题

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