前言
很多人都说熟悉 UIKit, 那对于常见的 API 是否熟悉?
多线程是前端经久不衰的考点.
大家对于 Block 的 weak-strong dance 都耳熟能详, 是否清楚知道每一个引用背后的持有者, 以及对象的具体释放时机?
来试试这 4 道精挑细选的题目.
正文
题目 1,UIImage 相关
看下面一段代码,
保存到相册的是什么?(从格式, 形状去描述)
- (void)testUIImage {
UIImage *testImage;
UIGraphicsBeginImageContext(CGSizeMake(50, 50));
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
testView.backgroundColor = [UIColor redColor];
testView.layer.cornerRadius = 25;
testView.layer.masksToBounds = YES;
[testView.layer renderInContext:UIGraphicsGetCurrentContext()];
testImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:testImage.CGImage metadata:nil completionBlock:nil];
}
题目 2,URL 相关
看下面一段代码,
写下三行 Log 的输出, 并解释下 URL 是什么.
- (void) testUrl {
NSString * path = @"https://www.baidu.com/";
NSString * path2 = @"http://fanyi.baidu.com/translate?query=#auto/zh/";
NSString * path3 = @"http://fanyi.baidu.com/translate?query=#zh/en / 测试";
NSURL * url = [NSURL URLWithString: path];
NSURL * url2 = [NSURL URLWithString: path2];
NSURL * url3 = [NSURL URLWithString: path3];
NSLog(@"%@", url);
NSLog(@"%@", url2);
NSLog(@"%@", url3);
}
题目 3, 线程相关
看下面一段代码,
写下 Log 的输出, 并解释为什么.
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"before perform");
[self performSelector:@selector(printLog) withObject:nil afterDelay:0];
NSLog(@"after perform");
});
}
- (void)printLog {
NSLog(@"printLog");
}
题目 4, 内存相关
看下面两段代码,
ViewController 的代码如下
- (void)testBtn {
LYButton *btn = [[LYButton alloc] init];
[self.view addSubview:btn];
[btn test];
[self.view addSubview:btn];
[btn test2];
}
LYButton 的代码如下
@implementation LYButton
- (void)test {
[self removeFromSuperview];
NSLog(@"%@", (self == nil) ? @"YES" : @"NO");
}
- (void)test2 {
__weak typeof (LYButton *) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf removeFromSuperview];
NSLog(@"%@", (weakSelf == nil) ? @"YES" : @"NO");
});
}
@end
写下 Log 的输出, 并解释为什么.
答案
题目 1
考察点: 对常见 UI 操作, 图片格式的了解.
内存中的 testImage 是非压缩的格式, 保存到相册可以使用 png 或者 jpeg 格式.
-writeImageToSavedPhotosAlbum:
接口默认用的 jpeg 的格式, 如果保存 png, 需要将图片转成 NSData, 然后再保存.
testView 的操作是绘制圆角按钮, 然后用 layer 的 renderInContext 绘制到 Context 中;
结果图
题目 2
考察点: 对 API 的 - URLWithString: 了解, 本质的知识点是 URL encode.
常见的错误是在 get 参数添加中文, 但是没有重新编码 (也叫转义), 导致 NSURL 初始化失败.
正确的做法是调用 NSString 的
(NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
方法.
URL:Uniform Resource Locator, 统一资源定位符, 用的是 ASCII 编码.
题目 3
考察点: GCD 并发队列实现机制, 以及 performSelector 的实现原理以及 runloop 了解.
上面这段代码, 只会打印 before perform 和 after perform, 不会打印 printLog.
原因:
1,GCD 默认的全局并发队列, 在并发执行任务的时候, 会从线程池获取可执行任务的线程 (如果没有就阻塞).
2,performSelector 的原理是设置一个 timer 到当前线程 Runloop, 并且是 NSDefaultRunLoopMode;
3, 非主线程的 runloop 默认是不启用;
进阶问题: 加一行代码使得 printLog 能正常打印.
题目 4
考察点: 内存的引用计数.
test1 中, removeFromSuperview 执行之前, 有 - testBtn,-test1,self.view 三个地方持有强引用, 到打印 log 的时候两个地方的强引用;
test2 中, 在 block 中强引用了 weakSelf, 当 block 执行的时候, testBtn 和 test2 的两个引用都已经释放, 当执行完 removeFromSuperview 之后, 最后一个引用也释放, 会立刻执行 dealloc 方法, weakSelf 被置为 nil(weak 指针的用法就是在对象被回收后变成 nil), 故而 Log 输出 YES;
类似, 在 UIButton 的 onClick: 回调方法中, button 类的 self 不仅会被 StackThread 持有, 还会被 main thread dispatch 持有 (系统分发点击事件).
总结
做题是一个有意思的过程, 短时间的思考并得到对 or 错的回馈, 非常适合人脑的学习模式.
希望这几道题能有所帮助. 如果错误, 请斧正.
来源: http://www.jianshu.com/p/941039aba684