2018年5月28日 ios面试3 runloop

1.

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];” 这句到底做什么?
是让主线程runloop进入休眠吗?不能理解为什么加了这句,代码就不会往下执行了?

 

一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入

 

https://blog.ibireme.com/2015/05/18/runloop/

 

https://blog.csdn.net/chenyong05314/article/details/14127767

 

 4种mode

Cocoa定义了四中Mode

Default:NSDefaultRunLoopMode,默认模式,在Run Loop没有指定Mode的时候,默认就跑在Default Mode下
Connection:NSConnectionReplyMode,用来监听处理网络请求NSConnection的事件
Modal:NSModalPanelRunLoopMode,OS X的Modal面板事件
Event tracking:UITrackingRunLoopMode,拖动事件
Common mode:NSRunLoopCommonModes,是一个模式集合,当绑定一个事件源到这个模式集合的时候就相当于绑定到了集合内的每一个模式

https://www.cnblogs.com/czc-wjm/p/5901324.html

 https://blog.csdn.net/gang544043963/article/details/79608129

 非主线程的runloop

@implementation AFURLConnectionOperation
@synthesize outputStream = _outputStream;

+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

 http://www.cocoachina.com/ios/20150601/11970.html

 

      Runloop接收两种源事件:input sources和timer sources。

 

      input sources 传递异步事件,通常是来自其他线程和不同的程序中的消息;

 

      timer sources(定时器) 传递同步事件(重复执行或者在特定时间上触发)。

性能

https://blog.csdn.net/opentogether/article/details/52447862

 

2.阿里

野指针

https://www.jianshu.com/p/4c8a68bd066c

 http://www.cocoachina.com/ios/20160707/16957.html

block copy

在MRC环境下,如果没有用__block,会对外部对象采用copy的操作,而用了__block则不会用copy的操作。

https://www.cnblogs.com/iOSJason/p/5605557.html

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

 1)synchronized性能

本文要说的就是最后一种 @synchronized 的用法。其实 @synchronized 用法很简单,首先 @synchronized() 小括号内需要一个参数,这个参数就表示信号量。这个参数可以是任何对象,包括 self,或者是自定义的信号量。针对不同的操作应该定义不同的信号量。

https://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/

https://www.jianshu.com/p/938d68ed832c#

 

2)sqlite锁

3)http2.0

4)urlsession

5)runloop的先决条件,为什么还需要循环

6)野指针

7)NSArray copy

因为NSString有对应的子类可变类型NSMutableString,且父类指针可以指向子类对象,如果不用copy而用strong,当传入的字符串是可变类型时, 并且这个字符串有改动时,就会导致属性的值也会改变。当然如果传入的字符串确定为不可变的,那么属性可以用strong修饰。 一些可变的类型如NSMutableString、NSMutabeArray、NSMutableDictionary一定得需要strong修饰,因为【object copy】返回的对象是不可变的,这时对可变对象进行修改就会崩溃。



https://www.jianshu.com/p/665e218c6ec1

 

 8)block  weak strong

9)block实现

10)类簇

 

这里没有使用self来调用,而是使用objc_getClass("__NSArrayM")来调用的。因为NSMutableArray的真实类只能通过后者来获取,而不能通过[self class]来获取,而method swizzling只对真实的类起作用。这里就涉及到一个小知识点:类簇。补充以上对象对应类簇表。

- (void)aac_forwardInvocation:(NSInvocation *)anInvocation {
    @try {
        [self aac_forwardInvocation:anInvocation];
    }
    @catch (NSException *exception) {
        [anInvocation invokeWithTarget:[_UnrecognizedSelectorProxy sharedInstance]];
        NSString *reason = [NSString stringWithFormat:@"%@ %@",exception.name,exception.reason];
        [AACManager recordCrashLogWithInstance:self type:AACTypeUnrecognizedSelector reason:reason];
    }
    @finally {

    }
}

阿里面试官问,try catch影响性能,已经判断了方法不存在,为什么还要try catch


https://github.com/tangbl93/AntiAPPCrash
 

6. 异常(Exceptions

不要使用C++异常。

优点:

1) 异常允许上层应用决定如何处理在底层嵌套函数中发生的“不可能发生”的失败,不像出错代码的记录那么模糊费解;

2) 应用于其他很多现代语言中,引入异常使得C++与Python、Java及其他与C++相近的语言更加兼容;

3) 许多C++第三方库使用异常,关闭异常将导致难以与之结合;

4) 异常是解决构造函数失败的唯一方案,虽然可以通过工厂函数(factory function)或Init()方法模拟异常,但他们分别需要堆分配或新的“非法”状态;

5) 在测试框架(testing framework)中,异常确实很好用。

缺点:

1) 在现有函数中添加throw语句时,必须检查所有调用处,即使它们至少具有基本的异常安全保护,或者程序正常结束,永远不可能捕获该异常。例如:if f() calls g() calls h()h抛出被f捕获的异常,g就要当心了,避免没有完全清理;

2) 通俗一点说,异常会导致程序控制流(control flow)通过查看代码无法确定:函数有可能在不确定的地方返回,从而导致代码管理和调试困难,当然,你可以通过规定何时何地如何使用异常来最小化的降低开销,却给开发人员带来掌握这些规定的负担;

3) 异常安全需要RAII和不同编码实践。轻松、正确编写异常安全代码需要大量支撑。允许使用异常;

4) 加入异常使二进制执行代码体积变大,增加了编译时长(或许影响不大),还可能增加地址空间压力;

5) 异常的实用性可能会刺激开发人员在不恰当的时候抛出异常,或者在不安全的地方从异常中恢复,例如,非法用户输入可能导致抛出异常。如果允许使用异常会使得这样一篇编程风格指南长出很多(译者注,这个理由有点牵强:-()!

http://www.cnblogs.com/vs2008_taotao/archive/2010/08/18/1801984.html

 

3.method swi

 

  • 实例一:替换ViewController生命周期方法
  • 实例二:解决获取索引、添加、删除元素越界崩溃问题
  • 实例三:防止按钮重复暴力点击
  • 实例四:全局更换控件初始效果
  • 实例五:App热修复
  • 实例六:App异常加载占位图通用类封装
  • 实例七:全局修改导航栏后退(返回)按钮

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

 

 

目前可以处理掉的crash类型具体有以下几种:

  • unrecognized selector crash

  • KVO crash

  • NSNotification crash

  • NSTimer crash

  • Container crash(数组越界,插nil等)

  • NSString crash (字符串操作的crash)

  • Bad Access crash (野指针)

  • UI not on Main Thread Crash (非主线程刷UI(机制待改善))

https://github.com/guoyuan94/CrashHopper/tree/59f8349af3667cbc2afd1fa4587802f765954b6c

 

    [NSObject swizzleInstanceMethod:@selector(forwardingTargetForSelector:) with:@selector(hopper_forwardingTargetForSelector:)];


...

#pragma mark - Unrecognized selector crash
- (id)hopper_forwardingTargetForSelector:(SEL)aSelector {
    if (!CRASHHOPPER_OPENING) {
        return [self forwardingTargetForSelector:aSelector];
    }

    id obj = [self hopper_forwardingTargetForSelector:aSelector];
    if (obj || ![self canForwardContinue] || [NSStringFromClass(self.class) hasPrefix:@"_"]) {
        return obj;
    }

    NSString *className = @"HopperClass";

    if ([self isKindOfClass:NSClassFromString(className)]) {
        return [NSNull null];
    }

    Class newClass = NSClassFromString(className);
    if (!newClass) {
        newClass = objc_allocateClassPair(NSObject.class, [className cStringUsingEncoding:NSUTF8StringEncoding], 0);
        objc_registerClassPair(newClass);
    }

    NSString *selString = NSStringFromSelector(aSelector);
    if (![self isSelctorAdded:selString inClass:newClass]) {
        NSString *className = NSStringFromClass(self.class);
        IMP imp = imp_implementationWithBlock(^(){
            NSException *exception = [NSException exceptionWithName:@"Unrecognized selector" reason:[NSString stringWithFormat:@"-[%@ %@]", className, selString] userInfo:nil];
            DEAL_CRASHHOPPERLOG
        });
        class_addMethod(newClass, aSelector, imp, selString.UTF8String);
    }

    return [newClass new];
}

代码有bug。

不过通过block转换为IMP时,需要注意,block不需要SEL,所以在block中只有一个默认参数self。在我们写block时,第一个参数必须为self,当函数调用的时候才能正确接收参数。

 

imp_implementationWithBlock(^(id self){

 

https://www.jianshu.com/p/6dcb18161fbb

 

 

+ (BOOL)resolveInstanceMethod:(SEL)sel {
  const GPBDescriptor *descriptor = [self descriptor];
  if (!descriptor) {
    return [super resolveInstanceMethod:sel];
  }

  // NOTE: hasOrCountSel_/setHasSel_ will be NULL if the field for the given
  // message should not have has support (done in GPBDescriptor.m), so there is
  // no need for checks here to see if has*/setHas* are allowed.
  ResolveIvarAccessorMethodResult result = {NULL, NULL};

#import "GPBMessage_PackagePrivate.h"

@interface GPBMessage () {

 

posted @ 2018-05-28 17:47  lianhuaren  阅读(153)  评论(0编辑  收藏  举报