iOS基础知识
iOS的内存管理
分为ARC、MRC两种,通过引用计数来控制对象,引用计数为0的时候,释放对象。
new、alloc、copy =1,retain +1,release -1。autorelease pool 是自动释放池,池子里的对象会等到池子释放时候一并释放,只释放计数为0的。
什么情况下会出现内存的循环引用?
循环引用是只相互强引用导致无法释放内存,造成内存泄露。
- Timer:timer一般为某个类的成员变量,创建timer的时候需要addTarget,这样timer就强引用了类,timer处于validate状态时,引用计数为1无法释放,若不手动释放,会出现循环引用;p.s.释放要在dealloc之前释放。
- block:block一般为某个类的成员变量,创建block的时候会对内部对象强引用,造成循环引用;解决方法为,将block内部的对象weak了再使用。如
__weak __typeof(&*self)weakself = self;
。 - delegate:delegate一般为某个类的成员变量,要用weak来修饰,否则容易出现循环引用。
block中的weak self,是任何时候都需要加的么?
在block中用到self时要加。
GCD的queue,main queue中执行的代码,一定是在main thread么?
queue不一定,main queue一定是main thread。
NSOperationQueue有哪些使用方式
- 添加operation
- 顺序执行operation(依赖、优先级)
- 设置并发数
- 取消所有operation(
[queue cancel]
) - 阻塞当前线程,等待queue的所有操作执行完毕 (
[queue waitUntilAllOperationsAreFinished]
) - 暂停继续queue
NSThread中的Runloop的作用,如何使用?
- 使程序一直运行并接收用户的输入
- 决定程序在何时处理哪些事件
- 节省CPU时间(当程序启动后,什么都没有执行的话,就不用让CPU来消耗资源来执行,直接进入睡眠状态)
每个线程(NSThread)对象中内部都有一个run loop(NSRunLoop)对象用来循环处理输入事件,处理的事件包括两类,一是来自Input sources的异步事件,一是来自Timer sources的同步事件;
[1]run Loop在处理输入事件时会产生通知,可以通过Core Foundation向线程中添加run-loop observers来监听特定事件,以在监听的事件发生时做附加的处理工作。 主线程的Run Loop会在App运行时自动运行,子线程中需要手动运行。
Run Loop就是一个处理事件源的循环,你可以控制这个Run Loop运行多久,如果当前没有事件发生,Run Loop会让这个线程进入睡眠状态(避免再浪费CPU时间),如果有事件发生,Run Loop就处理这个事件。
如果子线程进入一个循环需要不断处理一些事件,那么设置一个Run Loop是最好的处理方式,如果需要Timer,那么Run Loop就是必须的。
开发中遇到的需要使用Run Loop的情况有:
- 需要使用Port或者自定义Input Source与其他线程进行通讯。
- 子线程中使用了定时器
- 使用任何performSelector*****到子线程中运行方法
- 使用子线程去执行周期性任务
- NSURLConnection在子线程中发起异步请求
.h文件中的变量,外部可以直接访问么?(注意是变量,不是property)
不可以。访问变量需要有getter,直接访问会崩溃。
讲述一下runtime的概念,message send如果寻找不到相应的对象,会如何进行后续处理 ?
- 类:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
-
消息机制:
[receiver message]
会转化为objc_msgSend(receiver, selector)
-
方法调用过程:
先去缓存中找,没有去方法列表里找,再没有去父类的方法列表里找,如果找到则调用,实在找不到,动态方法解析,最后消息转发。 -
动态方法解析:
resolveInstanceMethod:
和resolveClassMethod:
两种。
void dynamicMethodIMP(id self, SEL _cmd) {
// implementation ....
}
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
@end
- 消息转发:
- 确定消息要发到哪里
- 将所有的参数一起发过去
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([someOtherObject respondsToSelector:[anInvocation selector]])
[anInvocation invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}
网友评论