当前的答案只是我自己的理解.(标题党来了).
完整答案请找👇🏻
题目出处
作者:Cooci_和谐学习_不急不躁
链接:https://www.jianshu.com/p/ec75262fc316
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
一、选择题(每题5分)
LGTeacher 继承于 LGPerson, 下面代码输出为什么 () 分值5分
LGTeacher *t = [[LGTeacher alloc] init];
- (instancetype)init{
self = [super init];
if (self) {
NSLog(@"%@ - %@",[self class],[super class]);
}
return self;
}
A: LGTeacher - LGTeacher
B: LGTeacher - LGPerson
C: LGTeacher - NSObject
D: LGTeacher - 它爱输出啥就输出啥,我不清楚
A [super class] 只是从父类开始找. 接受者还是self
下面代码能否正常执行以及输出 () 分值5分
@interface LGPerson : NSObject
@property (nonatomic, retain) NSString *kc_name;
- (void)saySomething;
@end
@implementation LGPerson
- (void)saySomething{
NSLog(@"%s - %@",__func__,self.kc_name);
}
@end
- (void)viewDidLoad {
[super viewDidLoad] ;
Class cls = [LGPerson class];
void *kc = &cls;
[(__bridge id)kc saySomething];
}
A: 能 - ViewController
B: 能 - null
C: 能 - ViewController: 0x7ff8d240ad30
D: 能不能自己运行一下不就知道,非要问我 - 它爱输出啥就输出啥,我不清楚
C 假设有一个LGPerson 的实例对象的内存结构是
isa 8
kc_name 8
第一句获取到类对象. 然后 kc = &cls .可以理解为kc 是一个isa指针指向了LGPerson 的类对象.
调用实例方法.打印kc_name. 也就是 *kc 接下去的8个字符.所代表的是什么.打印的就是什么. 所以应该是C
下面代码执行,控制台输出结果是什么 () 分值5分
NSObject *objc = [NSObject new];
NSLog(@"a:%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
void(^block1)(void) = ^{
NSLog(@"b:%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
};
block1();
void(^__weak block2)(void) = ^{
NSLog(@"c:%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
};
block2();
void(^block3)(void) = [block2 copy];
block3();
__block NSObject *obj = [NSObject new];
void(^block4)(void) = ^{
NSLog(@"d:%ld",CFGetRetainCount((__bridge CFTypeRef)(obj)));
};
block4();
A: 1 2 2 2 2
B: 1 2 3 3 2
C: 1 3 3 4 1
D: 1 3 4 5 1
答案是D
a是1.
block1 执行下面的时候.
void(^block1)(void) = ^{
NSLog(@"---%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
};
//会生成结构体
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
NSObject *__strong objc; 引用计数 +1
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSObject *__strong _objc, int flags=0) : objc(_objc) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr; // 方法的具体实现
};
在arc环境下.会自动给block 进行copy 操作.所以 b : 3
block2 执行
void(^__weak block2)(void) = ^{
NSLog(@"c:%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
};
block2();
跟b一样.生成strong指针指向objc +1.因为使用__weak 修饰.所以不会自动做copy操作. c:4
block3 执行
void(^block3)(void) = [block2 copy];
block3();
直接进行copy 操作 +1 . c 在打印一次 5
block4 执行
__block NSObject *obj = [NSObject new];
void(^block4)(void) = ^{
NSLog(@"d:%ld",CFGetRetainCount((__bridge CFTypeRef)(obj)));
};
block4();
//会将obj 直接转成block结构体
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_obj_0 *obj; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_obj_0 *_obj, int flags=0) : obj(_obj->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __Block_byref_obj_0 {
void *__isa;
__Block_byref_obj_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
NSObject *__strong obj; //数据存储在这里
};
// main调用变成
int main(int argc, const char * argv[]) {
//会将对象转成block结构体的对象
__Block_byref_obj_0 obj = {(void*)0,
(__Block_byref_obj_0 *)&obj,
33554432,
sizeof(__Block_byref_obj_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("new"))
};
void(*block4)(void) = &__main_block_impl_0(__main_block_func_0,
&__main_block_desc_0_DATA,
(__Block_byref_obj_0 *)&obj,
570425344));
((__block_impl *))((__block_impl *)block4)->FuncPtr)((__block_impl *)block4);
}
return 0;
}
会将对象转成block 的对象.所以d : 1
下面代码执行,控制台输出结果是什么 () 分值5分
- (void)MTDemo{
while (self.num < 5) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"KC : %d",self.num);
}
- (void)KSDemo{
for (int i= 0; i<10000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"Cooci : %d",self.num);
}
A: 0 , 10000
B: 0 , <10000
C: <=5 , <10000
D: >=5 , <10000
D
下面代码执行,控制台输出结果是什么 () 分值5分
- (void)textDemo2{
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
}
- (void)textDemo1{
dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
}
A: 1 5 2 3 4 , 1 5 2
B: 1 5 2 4 3 , 死锁奔溃
C: 1 5 2 3 4 , 死锁奔溃
D: 1 5 2 3 , 死锁奔溃
C 15234 152死锁
题目问的是终端打印什么 .所以应该是A (手动捂脸)
下面代码执行,控制台输出结果是什么 () 分值5分
@property (nonatomic, strong) NSMutableArray *mArray;
- (NSMutableArray *)mArray{
if (!_mArray) _mArray = [NSMutableArray arrayWithCapacity:1];
return _mArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
self.mArray = arr;
void (^kcBlock)(void) = ^{
[arr addObject:@"3"];
[self.mArray addObject:@"a"];
NSLog(@"KC %@",arr);
NSLog(@"Cooci: %@",self.mArray);
};
[arr addObject:@"4"];
[self.mArray addObject:@"5"];
arr = nil;
self.mArray = nil;
kcBlock();
}
A: 1 2 4 5 3 , nil
B: 1 2 4 5 3 , a
C: 1 2 4 5 3 , 1 2 4 5 3 a
D: 1 2 4 5 3 a , 1 2 4 5 3 a
B
二、判断题 (每题5分)
可变数组线程是安全 () 分值5分
对
错
错
主队列搭配同步函数就会产生死锁 () 分值5分
对
错
错
下面代码执行不会报错 () 分值5分
int a = 0;
void(^ __weak weakBlock)(void) = ^{
NSLog(@"-----%d", a);
};
struct _LGBlock *blc = (__bridge struct _LGBlock *)weakBlock;
id __strong strongBlock = [weakBlock copy];
blc->invoke = nil;
void(^strongBlock1)(void) = strongBlock;
strongBlock1();
对
错
对
下面代码执行不会报错 () 分值5分
NSObject *a = [NSObject alloc];
void(^__weak block1)(void) = nil;
{
void(^block2)(void) = ^{
NSLog(@"---%@", a);
};
block1 = block2;
NSLog(@"1 - %@ - %@",block1,block2);
}
block1();
对
错
错.会报错
下面代码会产生循环引用 () 分值5分
__weak typeof(self) weakSelf = self;
self.doWork = ^{
__strong typeof(self) strongSelf = weakSelf;
weakSelf.doStudent = ^{
NSLog(@"%@", strongSelf);
};
weakSelf.doStudent();
};
self.doWork();
对
错
会产生循环引用
下面代码是否有问题 () 分值5分
- (void)demo3{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<5000; i++) {
dispatch_async(concurrentQueue, ^{
NSString *imageName = [NSString stringWithFormat:@"%d.jpg", (i % 10)];
NSURL *url = [[NSBundle mainBundle] URLForResource:imageName withExtension:nil];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
dispatch_barrier_async(concurrentQueue, ^{
[self.mArray addObject:image];
});
});
}
}
对
错
对.有问题.
dispatch_barrier_async 没有效果.在全局并发队列 barrier 无法生效
下面代码不会产生循环引用 () 分值5分
static ViewController *staticSelf_;
- (void)blockWeak_static {
__weak typeof(self) weakSelf = self;
staticSelf_ = weakSelf;
}
对
错
不会
三、简单题 (每题 10分 合计 120分)
请把它当成一场面试,认真对待 希望大家耐心 切忌浮躁 (和谐学习 不急不躁)
1、请用GCD实现读写锁 , 解释为什么这么设计 分值10分
其实就是多读单写.使用自己创建的并发队列.然后使用barrier进行写入的操作.就好.
2、@synchronized 为什么应用频次最多 分值10分
最根本原因肯定是因为写法简单粗暴.
本质是一个递归锁.
3、block 的种类有几种 是符合区分的? 分值10分
global 全局
malloc 堆
stack 栈
4、KVC 普通对象 setter 过程 分值10分
5、KVO 底层原理机制分析 分值10分
创建当前类的子类.然后将当前类的isa 指向子类.重写监听的对象的set 方法
willchanggevalueforkey
super set
didchangevalueforkey
6、下面代码的栈帧入栈情况是什么的? 分值10分
- (void)viewDidLoad {
[super viewDidLoad] ;
Class cls = [LGPersonP class];
void *kc = &cls;
[(__bridge id)kc saySomething];
LGPersonP *person = [LGPersonP alloc];
}
- LGPersonP
- Viewcontroller : 内存地址
- 其他接下去的地址
7、iOS 线程如何保活, 为什么要线程保活 分值10分
线程如何保活.通过给runloop 添加source0/source1/timer/observer 都可以.一般的做法就是给source1添加一个port.然后在当前线程进行run.
为什么线程保活: 主要是考虑业务上的问题.用空间换时间.比如网络请求.可能需要频繁的进行网络请求.这时候.我们创建一个子线程.然后需要用的时候.直接调用就行
8、循环引用,为什么要在block中加strong,不加会怎样 分值10分
保证在block运行的时候.内部的对象不要释放
9、你使用过 dispatch_once 吗?了解底层吗?让你实现一个应该怎么操作? 分值10分
10、iOS 多线程原理和线程生命周期是什么样的 分值10分
11、请简述信号量和调度组的原理 分值10分
12、请简述 __block 修饰变量被 block 捕获之后的情况 分值10分
被__block修饰的对象.最后本质会变成一个X_block_impl_X结构体.
四、拓展满分题 (15分)
作为一名iOS中高级开发人员, 你的加分项和优势是什么?
略