面试题(主要通过OC举例,Swift语法相关待更新)
main函数解析
int main(int argc, char * argv[]) {
@autoreleasepool {
/**
* argc,argv是C标准main函数的参数,直接传递给UIApplicationMain进行相关处理即可;
principalClassName:指定应用程序类,该类必须是UIApplication类或其子类。如果为nil,则用UIApplication类作为默认值
delegateClassName:指定应用程序类的代理类,该类必须遵循UIApplicationDelegate协议,此函数会根据principalClassName创建UIApplication对象,根据delegateClassName创建一个delegate对象,并将该delegate对象赋值给UIApplication对象中的delegate属性。UIApplication对象会依次给delegate对象发送不同的消息,接着会创建应用程序的main runloop(事件循环),进行事件的处理(首先会调用delegate对象的 application:didFinishLaunchingWithOptions : ) 程序正常退出时这个函数才返回。
UIApplication 对象管理事件循环和高层的应用行为
应用委托是应用的核心,该对象与UIApplication对象联合起来负责对应用的初始化过程、状态迁移过程和很多高层的应用事件进行处理
*/
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
复制代码
举例:GCD使用
1)串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 10; i ++) {
dispatch_async(serialQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@">>>%d", i);// 此处做UI刷新,如排行榜头像顺序显示
});
});
}
复制代码
或(使用dispatch_apply,不立即返回,打印执行结果是1243)
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_apply(10, queue, ^(size_t i) {
NSLog(@"2");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"3");
});
});
NSLog(@"4");
复制代码
2)并行队列
// (参数一:线程优先,参数二:标记参数)
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < count; i ++) {
dispatch_async(globalQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@">>>%d", i);// 此处做UI刷新
});
});
}
复制代码
或
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, queue, ^(size_t i) {
NSLog(@"%@我开始执行 %zu times", [NSThread currentThread], i+1);
});
NSLog(@"done");
复制代码
3)多个异步任务,同时返回处理
NSLog(@"全部开始-----%@", [NSThread currentThread]);
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{
sleep(4);
NSLog(@"子线程1-----%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
sleep(3);
NSLog(@"子线程2-----%@", [NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"全部结束-----%@", [NSThread currentThread]);
});
复制代码
4)多个请求,同时返回处理
NSLog(@"即将开始多个请求");
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
[[URLBase sharedInstance] getBusinessDataWithSuccess:^(NSDictionary *result) {
dispatch_group_leave(group);
NSLog(@"请求1完成");
} failure:^(NSError *error) {
dispatch_group_leave(group);
}];
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
[[URLBase sharedInstance] getHomeConfigurationWithSuccess:^(NSDictionary *result) {
dispatch_group_leave(group);
NSLog(@"请求2完成");
} failure:^(NSError *error) {
dispatch_group_leave(group);
}];
});
dispatch_group_notify(group, queue, ^{
NSLog(@"全部完成");
});
复制代码
举例:核心动画
// 1、CAAnimation-抽象类、父类,控制持续时间和速度,不直接使用
// 2、CABasicAnimation-基本动画
CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"position"];
anima.fromValue = [NSValue valueWithCGPoint:CGPointMake(a, b)];
anima.toValue = [NSValue valueWithCGPoint:CGPointMake(c, d)];
anima.duration = 1.0f;
[someView.layer addAnimation:anima forKey:@"positionAnimation"];
// 3、CAKeyframeAnimation-关键帧动画
// 4、CAAnimationGroup-动画组
// 5、CATransition-转场动画
复制代码
OC发射机制
获取类:[self class]
判断关系:isKindOfClass(判断是否是这个类或它的子类实例)、isMemberOfClass(判断是否是这个类的实例)
动态调用方法等:performSelector:(SEL)
线程之间的通信方式
performSelectorOnMainThread: withObject: waitUntilDone:
performSelector: onThread: withObject: waitUntilDone:
dispatch_get_global_queue(0,0)
dispatch_get_main_queue()
复制代码
OC可以多重继承吗
不行,C++可以,OC通过实现多个接口达到相似效果
id声明的对象有什么特性
运行时runtime特性,可以指向任意OC对象
原子(atomic)非原子(nonatomic)区别
atomic:
- 是默认的
- 线程安全,能在别的线程来访问这个属性之前,先执行完当前流程
- 速度不快,因为要保证操作整体完成
nonatomic:
- 不是默认的
- 更快
- 线程不安全
- 如有两个线程访问同一个属性,会出现无法预料的结果
分类category与类扩展extension、继承的区别
类别 -只能新增方法(编译时categroy的内存布局已经确定,没有ivar,所以不能添加属性,需要重写set和get方法进行runtime属性关联);
类扩展 -可以新增属性(必须有类的源码才行);
继承 -可以增删改方法及属性;
tips:
多个category的调用顺序按照:Build Phases ->Complie Source 中的编译顺序
修饰符总结
基本数据类型 - assign(assign可修饰数据和对象、weak只对象;assign修饰对象释放后,指针不会置空);
NSString/Block - copy(用strong、copy修饰的区别,strong修饰时被赋值一个可变字符串对象,会强引用这个对象,当对象改变时,属性值也跟着变了);
delegate - weak(防止循环引用,无法释放delegate对象);
其他指针对象 - strong;
xib/storyboard - weak;
自定义UI - strong;
OC与JS交互:
-拦截url进行跳转
-JavaScriptCore(只适用于UIWebView)
-遵循协议:WKScriptMessageHandler(只适用于WKWebView)
OC与Swift特性及混编
特点:
OC:面向对象的C语言的延伸,具有runtime、runloop,MRC,ARC等特性;
Swift:继承OC面向对象的特点,具有简洁高效安全的语法特色,支持边写边看Playground/SwiftUI,以及泛型、可选型、元组、字符串枚举等特点;
混编:
OC调用Swift:import “ProjectName-Swift.h”
Swift调用OC:import “ProjectName-Bridging-Header.h”
Get和Post区别:
(1)post更安全(不会作为url的一部分,不会被缓存、保存在服务器日志、以及浏览器浏览记录中)
(2)post发送的数据更大(get有url长度限制)
(3)post能发送更多的数据类型(get只能发送ASCII字符)
(4)post比get慢(post多了一些额外字段,先发送head确认,再发送body)
什么是block
block是封装了函数调用及环境的OC对象,本质是结构体,内部也有isa指针。
block为什么用copy(retain)修饰
block默认是声明为栈变量的(栈区的特点就是创建的对象随时可能被销毁),为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆。
什么是isa指针
类似isKindOf,指向所属类的指针。对象—>类对象—>父类—>元类—>根类(NSObject)
设置信号量
1)dispatch_semaphore_create(0):创建一个Semaphore并初始化信号的总量;
2)dispatch_semaphore_wait(name, DISPATCH_TIME_FOREVER):可以使总信号量-1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行;
3)dispatch_semaphore_signal(name):发送一个信号,让信号总量+1;
消息转发机制(objc_msgSend(target, @selector(doSomething)))
-查找方法缓存:cache_t
-找实际方法:对象isa->类->父类->元类->基类,method_list
-动态方法解析:resolveClassMethod(类)、resolveInstanceMethod(对象);addMethodWithClass(动态添加方法补救)
-消息转发流程:
快速转发:forwardingTargetForSelector(返回备用对象)
标准转发:methodSignatureForSelector(SEL方法的签名)、forwardInvocation(创建备用对象看是否响应SEL,无法响应则doesNotRecognizeSelector)
weak实现原理
Runtime维护了一个weak表(hash表),用于存储指向某个对象的所有weak指针。Key是所指对象的地址,Value是weak指针。
1、初始化:objc_initWeak
2、添加:objc_storeWeak()
3、释放:clearDeallocating,循环遍历->weak指针 = nil->移除weak表记录
对象序列化和反序列化
model类实现NSCodeing协议:
-(void)encodeWithCoder:(NSCoder *)aCoder;
-(instancetype)initWithCoder:(NSCoder *)aDecoder;
运用:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:model];
Model *model = [NSKeyedUnarchiver unarchiveObjectWithData:data];
深浅拷贝简述
浅拷贝 复制指针,retainCount +1
深拷贝 复制内容,retainCount 不变
[不可变对象 copy] 不可变,浅拷贝
[不可变** mutableCopy] 可变,深拷贝
[可变** copy] 可变,深拷贝
[可变** mutableCopy] 可变,深拷贝
一对多代理如何实现?(多播代理)
将一对一的delegate,委托给一个单例,需要完成代理业务的界面实现单例对外的block/delegate等
autoreleasepool的原理和使用场景?
若干个autoreleasepoolpage组成的双向链表的栈结构,objc_autoreleasepoolpush、objc_autoreleasepoolpop、objc_autorelease
使用场景:多次创建临时变量导致内存上涨时,需要延迟释放
autoreleasepoolpage的内存结构:4k存储大小
属性多读单写(多线程可读单线程写)如何实现?
使用线程锁:@synchronized、NSLock、dispatch_semaphore
AFN多线程通过什么管理?
NSOperationQueue
SDWebImage的cache原理?
存储在内存和硬盘中,可设置是否cache到硬盘。先查找内存,不存在,再查找硬盘;查找硬盘时,以URL的MD5值作为key;不存在,再执行下载;下载完毕保存内存和硬盘。
NSArray与NSSet的区别?
NSArray内存中存储地址连续,而NSSet不连续;
NSSet效率高,内部使用hash查找,NSArray查找需要遍历;
NSSet通过anyObject访问元素,NSArray通过下标访问;
对iOS类私有属性的访问和修改有两种方法:
KVC、Runtime(重写set、get,类似分类,进行属性关联)
写一个线程安全的单例模式
static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
+ (instancetype)sharedData {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
// 遵循NSCopying协议
- (id)copyWithZone:(NSZone *)zone {
return _instance;
}
复制代码
instancetype和id的异同
1)相同点
都可以作为方法的返回类型
2)不同点
①instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
②instancetype只能作为返回值,不能像id那样作为参数
扩展知识点
静态库生成,支持真机和模拟器
1)shift+command+n -> framework
2)Edit Scheme -> Run -> Release
3)Build Setting -> Mach-O Type -> Static Library
4)Build Phases -> Headers -> Public
5)Coding&add files
6)command+b
7)lipo -create 真机路径 模拟器路径 -output 真机路径
内存讲解
iOS内存分为5个区:栈区,堆区,全局区,常量区,代码区(从左到右由高地址像低地址)。
- 栈区stack:这一块区域系统会自己管理,我们不用干预,主要存一些局部变量,以及函数跳转时的现场保护。
- 堆区heap:与栈区相对,这一块一般由我们自己管理,比如alloc,free的操作,存储一些自己创建的对象。
- 全局区(静态区static):全局变量和静态变量都存储在这里,已经初始化的和没有初始化的会分开存储在相邻的区域,程序结束后系统会释放。
- 常量区:存储常量字符串和const常量
- 代码区:存储代码
lldb (gdb)常用的控制台调试命令?
1). p(print) 输出数据类型及对应值
2). po(print-object) 打印对象
3). expr(expression) 调试时动态执行表达式/赋值,并将结果打印出来
4). bt:打印调用堆栈
性能调优
耗电(intrument)、内存泄漏(analyze,Memery Leak)、启动速度(无用重复代码清理、framework优化、延迟、异步)、包体瘦身(冗余代码、减少xib、废弃文件、废弃图片)
工具:intrument、analyze、memery leak、断点调试
数据库增删改查
增:INSERT or REPLACE INTO t1 (a,b,c,d) VALUES (1,2,3,4)
删:DELETE FROM t1 WHERE userid=110
改:UPDATE t1 set name=‘abc’ WHERE userid=110
查:SELECT * FROM t1 LEFT JOIN t2 ON t1.userid=t2.userid WHERE userid NOT IN (SELECT userid FROM t3) AND sex=1 order by datetime(createtime) DESC/ASC
数量查询:SELECT count(distinct userid) as someCount FROM t1 WHERE name=‘abc’
组件化
好处:代码清晰易用、解耦合
推荐模式:target-action
(组件—>target(中间件,封装了组件的调用)—>category(CTMediator分类,通过发射机制(NSClassFromString/NSSlectorFromString)提供runtime服务)—>外层调用)
中心思想:①、封装公共库和基础UI库 ②、独立业务模块化 ③、接口调用最小化
私聊历史消息翻页如何进行刷新?
开始更新-插入/删除行-结束更新
- (void)beginUpdates;
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)endUpdates;
复制代码
举例:算法-快速排序
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@5,@2,@6,@7,@1,@3,@8,@4, nil];
printf("排序前:");
[self printArr:arr];
[self quickSort:arr low:0 high:(int)arr.count-1];
printf("排序后:");
[self printArr:arr];
- (void)printArr:(NSArray *)arr {
for (NSNumber *num in arr) {
printf("%d ", num.intValue);
}
printf("\n");
}
- (void)quickSort:(NSMutableArray *)arr low:(int)low high:(int)high {
// 1、安全判断
if (arr == nil || arr.count == 0) {
return;
}
if (low >= high) {
return;
}
// 2、找到中间位索引、值
int middle = low + (high - low)/2;
int middleNum = [arr[middle] intValue];
// 3、i从低位开始,j高位开始循环,与中值做比较符合条件调换位置
int i = low;
int j = high;
while (i <= j) {
// 升序,降序改为 >
while ([arr[i] intValue] < middleNum) {
i++;
}
// 升序,降序改为 <
while ([arr[j] intValue] > middleNum) {
j--;
}
if (i <= j) {
[arr exchangeObjectAtIndex:i withObjectAtIndex:j];
i++;
j--;
}
printf("排序中:");
[self printArr:arr];
}
// 4、继续下一轮比较
if (low < j) {
[self quickSort:arr low:low high:j];
}
if (high > i) {
[self quickSort:arr low:i high:high];
}
}
复制代码
沙盒结构:
1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文件,否则上架不被通过)
3). Library:
Caches:存放体积大又不需要备份的数据。(常用的缓存路径)
Preference:设置目录,iCloud会备份设置信息。
4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。