面试题
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。如:
1 2 3 | 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]; |
或者
1 2 | 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 客户端在解析服务端所下发的数据时,例如下面的代码片段:
1 2 3 4 5 | 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类型)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #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 当进入一个页面时添加任务到后台线程,例如下面的代码片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - ( 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。则队列中的任务将不再会执行,也就相当于是取消了未执行的任务。
1 2 3 4 5 6 7 8 9 10 11 | __weak typeof( self ) weakSelf = self ; dispatch_async( self .queue, ^{ if (weakSelf.isStart) { NSLog (@ "%ld" , i); } }); |
6 有如下代码:
1 2 3 4 5 6 7 | -( void )dealloc { _weak _typeof( self ) weak_self = self ; NSLog (@“%@”, weak_self); } |
请问,当执行该方法时会出现审结果?为什么?
崩溃。原因是不允许在dealloc中取weak self
崩溃时在控制台打印出的信息时:
1 | 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 的函数代码,找到问题所在。
weak_register_no_lock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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 有如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 在主线程执行 同步执行
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
2017-03-09 Mac环境下svn的使用(转)