面试题

1 如何实现一个图片加载控件(包括图片下载、缓存时效、加载)?

  参考链接:http://blog.csdn.net/tengxy_cloud/article/details/52869037 

2 JavaScriptCore是做什么用的,客户端使用它可实现什么功能?

3 程序中添加每3秒响应一次的NSTimer,当拖动tableView时timer可能无法响应,为什么,要怎么解决?

   scheduled开头和非schedule的开头方法的区别。系统框架提供了几种创建NSTimer的方法,其中以scheduled开头的方法会自动把timer加入当前run loop,到了设定的时间点就会触发指定的方法,而没有scheduled开头的方法则需要程序员自己手动添加到timer到一个run loop中才会有效。run loop在运行时一般有两个mode,一个defaultmode,一个trackingmode,正常情况下run loop使用defaultmode,scheduled生成的timer会默认添加到defaultmode中,当我们互动scrollview时,run loop切换到trackingmode运行,于是我们发现定时器失效了。为了使定时器在我们滑动scrollview时也能正常运行,我们需要确保defaultmode和trackingmode里都添加了我们生成的timer。如:

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(scrollPage) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

 或者

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(scrollPage) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

  在使用NSTimer时应注意:

(1)使用NSTimer时,timer会保持对target和userInfo参数的强引用。只有当调取了NSTimer的invalidate方法时,NSTimer才会释放target和userInfo。生成timer的方法中如果repeats参数为NO,则定时器触发后会自动调取invalidate方法。如果repeats参数为YES,则需要程序员手动调取invalidate方法才能释放timer对target和userIfo的强引用。

(2)在使用repeats参数为YES的定时器时,如果在使用完定时器时后没有调取invalidate方法,导致target和userInfo没有被释放,则可能会形成循环引用情况,从而影响内存释放。

4 客户端在解析服务端所下发的数据时,例如下面的代码片段:

NSString *sku = dict[@"sku"];

NSMutableArray *array = [NSMutableArray array];

[array addObject:sku];

可能@"sku"字段并不存在,sku对象将为nil,执行[array addObject:sku]时将会抛出异常导致Crash。项目中可能很多模块存在类似这样的问题,请从全局考虑,如何进行异常保护?

注意:在类簇中实现Method Swizzling。 NSMutableArray-----@"__NSArrayM"(用Xcode调试时,在下方debug区域显示的__NSArrayM类型)

#import "NSMutableArray+Swizzling.h"
#import <objc/runtime.h>

@implementation NSMutableArray (Swizzling)

+ (void)load {   
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class originClass = NSClassFromString(@"__NSArrayM");
        Class swizzledClass = [self class];
        
        SEL originalSelector = @selector(addObject:);
        SEL swizzledSelector = @selector(xxx_addObject:);
        
        Method originalMethod = class_getInstanceMethod(originClass, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector);
        
        BOOL didAddMethod = class_addMethod(originClass,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(originClass,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }); 
}

- (void)xxx_addObject:(id)object {    
        if (object != nil) {
            [self xxx_addObject:object];
        }
}

@end

5 当进入一个页面时添加任务到后台线程,例如下面的代码片段:

- (void)viewDidLoad {

    [super viewDidLoad];

    self.queue = dispatch_queue_create("jd.test", DISPATCH_QUEUE_SERIAL);

    for (NSInteger i = 0; i < 10; i ++) {

        dispatch_async(self.queue, ^{

            NSLog(@"%ld", i);

        });

    }

}

在页面退出时,假如队列中执行到第3个任务,如何取消还没有执行的任务?

   设置一个全局标识Bool isStart = YES,在队列中异步执行任务时,判断这个标识isStart是否为YES,如果是YES再执行,否则不执行。当页面退出时,我们在dealooc方法中将这个标识设置为isStart = NO。则队列中的任务将不再会执行,也就相当于是取消了未执行的任务。

  __weak typeof(self) weakSelf = self;  

  dispatch_async(self.queue, ^{

    if (weakSelf.isStart) {

      NSLog(@"%ld", i);

    }     

        });

6 有如下代码:

-(void)dealloc {

_weak _typeof(self) weak_self = self;

NSLog(@“%@”, weak_self);

}

请问,当执行该方法时会出现审结果?为什么?

   崩溃。原因是不允许在dealloc中取weak self

  崩溃时在控制台打印出的信息时: 

 Cannot form weak reference to instance (0x160f6f890) of class MFChatRoomBoardController. It is possible that this object was over-released, or is in the process of deallocation.


查看了一下 weak_register_no_lock 的函数代码,找到问题所在。


id weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id)
{
    objc_object *referent = (objc_object *)referent_id;
    objc_object **referrer = (objc_object **)referrer_id;

    if (!referent  ||  referent->isTaggedPointer()) return referent_id;

    // ensure that the referenced object is viable
    bool deallocating;
    if (!referent->ISA()->hasCustomRR()) {
        deallocating = referent->rootIsDeallocating();
    }
    else {
        BOOL (*allowsWeakReference)(objc_object *, SEL) = 
            (BOOL(*)(objc_object *, SEL))
            object_getMethodImplementation((id)referent, 
                                           SEL_allowsWeakReference);
        if ((IMP)allowsWeakReference == _objc_msgForward) {
            return nil;
        }
        deallocating =
            ! (*allowsWeakReference)(referent, SEL_allowsWeakReference);
    }

    if (deallocating) {
        _objc_fatal("Cannot form weak reference to instance (%p) of "
                    "class %s. It is possible that this object was "
                    "over-released, or is in the process of deallocation.",
                    (void*)referent, object_getClassName((id)referent));
    }

    // now remember it and where it is being stored
    weak_entry_t *entry;
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
        append_referrer(entry, referrer);
    } 
    else {
        weak_entry_t new_entry;
        new_entry.referent = referent;
        new_entry.out_of_line = 0;
        new_entry.inline_referrers[0] = referrer;
        for (size_t i = 1; i < WEAK_INLINE_COUNT; i++) {
            new_entry.inline_referrers[i] = nil;
        }

        weak_grow_maybe(weak_table);
        weak_entry_insert(weak_table, &new_entry);
    }

    // Do not set *referrer. objc_storeWeak() requires that the 
    // value not change.

    return referent_id;
}

可以看出,runtime 是通过检查引用计数的个数来判断对象是否在 deallocting, 然后通iif (deallocating)使程序崩溃。

7 有如下代码:

typedef void (^TestBlock)(void);

int main(int argc, char * argv[]) {

    @autoreleasepool {        

        NSString *test = @"test";

        TestBlock block = ^(void) {

            dispatch_sync(dispatch_queue_create("jd.test", DISPATCH_QUEUE_SERIAL), ^{

                NSLog(@"%@", test);

            });

        };

        test = @"test1";

        block();

    }

}

请问,NSLog(@“%@”, test)的输出结果是什么?这条语句在哪个线程执行?为什么?

  输出结果:test  在主线程执行       同步执行

原文地址:https://www.cnblogs.com/GJ-ios/p/8534010.html