1.说下线程和进程的区别。
线程是CPU独立运行和独立调度的基本单位(可以理解为一个进程中执行的代码片段)。
进程是资源分配的基本单位(进程是一块包含了某些资源的内存区域)。
进程有独立的地址空间,一个进程崩溃后,在保护模式的影响下不会对其他进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等同于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程是线程的容器,真正完成代码执行的线程,而进程则作为线程的执行环境。一个程序至少包含一个进程,一个进程至少包含一个线程,一个进程中的所有线程共享当前进程所拥有的资源。
2.了解哪些设计模式
设计模式大概分成三类:
1.创建型:单例设计模式、抽象工厂设计模式
2.结构型:MVC 模式、装饰器模式、适配器模式、外观模式、组合模式
3.行为型:责任链设计模式、观察者设计模式,备忘录设计模式、命令设计模式
单例设计模式有如下特点:
1.单例设计模式确保对于一个给定的类只有一个实例存在,这个实例有一个全局唯一的访问点。
2.它通常采用延迟加载的方式在第一次用到实例的时候再去创建它。
[NSUserDefaults standardUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager],所有的这些方法都返回一个单例对象
单例模式实现步骤:
1.声明一个静态变量去保存类的实例,确保它在类中的全局可用性。
2.声明一个静态变量dispatch_once_t ,它确保初始化器代码只执行一次
3.使用Grand Central Dispatch(GCD)执行初始化LibraryAPI变量的block.这 正是单例模式的关键:一旦类已经被初始化,初始化器永远不会再被调用。
下一次你调用sharedInstance的时候,dispatch_once块中的代码将不会执行(因为它已经被执行了一次),你将得到原先已经初始化好的实例。
3.MVVM
很简单,处理视图展示逻辑,ViewModel负责将数据业务层提供的数据转化为界面展示所需的VO。其与View一一对应,没有View就没有ViewModel
4.即时通讯
环信SDK,腾讯的融云SDK。
5.支付
1.支付宝
创建应用和KEY支付宝支付创建
新版之后只需要导入两个文件就可以解决了,文件如下:
AlipaySDK.framework
AlipaySDK.bundle
一般前端客户端只需要传递给后台价格 和商品ID,请求后台服务器接口。后台在将价格等参数一一对应返回给 前端订单信息orderInfo,md5Sign,orderSign,out_trade_no。四个参数。第一步根据订单信息orderInfo + 自己与后台定义的key用MD5加密。加密得到的值是否和参数md5Sign相同。如果相同,则订单信息加密正确。
将商品信息拼接成字符串 signStr = orderSign .encodeString
最后生成一个orderInfo + sign = signStr + sign_type = RSA
启动支付宝
[[AlipaySDK defaultService] payOrder:orderString fromScheme:[self qw_appScheme] callback:^(NSDictionary *resultDic) { }];
2.微信支付
商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。点击打开链接
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。点击打开链接
步骤5:商户后台接收支付通知。点击打开链接
步骤6:商户后台查询支付结果。点击打开链接
(一般这些商户信息都交给后台操作)
3.苹果内购
可参考苹果内购
6.使用了第三方库, 有看他们是怎么实现的吗?
SD、YY、AFN、MJ
1.入口 setImageWithURL:placeholderImage:options:会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。查找是否缓存了图片。先从内存缓存中查找,没有再从硬盘查找,根据URLKey在硬盘缓存目录读取。否则回调 imageCache:didNotFindImageForKey:userInfo:下载图片。共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
2.MJ刷新原理iOS-MJRefresh框架底层实现原理利用scrollView在滚动,就会调用这个代理方法。UIEdgeInsetsinset =self.tableView.contentInset; inset.top+=self.header.height;self.tableView.contentInset = inset;
7.遇到tableView卡顿嘛?会造成卡顿的原因大致有哪些
1.最常用的就是cell的重用, 注册重用标识符
如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell;
如果有很多数据的时候,就会堆积很多cell。
如果重用cell,为cell创建一个ID,每当需要显示cell 的时候,都会先去缓冲池中寻找可循环利用的cell,如果没有再重新创建cell
2.避免cell的重新布局
cell的布局填充等操作 比较耗时,一般创建时就布局好
如可以将cell单独放到一个自定义类,初始化时就布局好
3.提前计算并缓存cell的属性及内容
当我们创建cell的数据源方法时,编译器并不是先创建cell 再定cell的高度
而是先根据内容一次确定每一个cell的高度,高度确定后,再创建要显示的cell,滚动时,每当cell进入凭虚都会计算高度,提前估算高度告诉编译器,编译器知道高度后,紧接着就会创建cell,这时再调用高度的具体计算方法,这样可以方式浪费时间去计算显示以外的cell
4.减少cell中控件的数量
尽量使cell得布局大致相同,不同风格的cell可以使用不用的重用标识符,初始化时添加控件,
不适用的可以先隐藏
5.不要使用ClearColor,无背景色,透明度也不要设置为0
渲染耗时比较长
6.使用局部更新
如果只是更新某组的话,使用reloadSection进行局部更新
7.加载网络数据,下载图片,使用异步加载,并缓存
8.少使用addView 给cell动态添加view
9.按需加载cell,cell滚动很快时,只加载范围内的cell
10.不要实现无用的代理方法,tableView只遵守两个协议
11.缓存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同时存在,这两者同时存在才会出现“窜动”的bug。所以我的建议是:只要是固定行高就写预估行高来减少行高调用次数提升性能。如果是动态行高就不要写预估方法了,用一个行高的缓存字典来减少代码的调用次数即可
12.不要做多余的绘制工作。在实现drawRect:的时候,它的rect参数就是需要绘制的区域,这个区域之外的不需要进行绘制。例如上例中,就可以用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判断是否需要绘制image和text,然后再调用绘制方法。
13.预渲染图像。当新的图像出现时,仍然会有短暂的停顿现象。解决的办法就是在bitmap context里先将其画一遍,导出成UIImage对象,然后再绘制到屏幕;
14.使用正确的数据结构来存储数据。
8.编译过程做了哪些事情
Objective和Swift。二者都是编译语言,换句话说都是需要编译才能执行的。二者的编译都是依赖于Clang + LLVM. OC和Swift因为原理上大同小异。
9.字典大致实现原理
NSDictionary(字典)是使用hash表来实现key和value之间的映射和存储的
方法:- (void)setObject:(id)anObject forKey:(id)aKey;
Objective-C中的字典NSDictionary底层其实是一个哈希表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
哈希概念:哈希表的本质是一个数组,数组中每一个元素称为一个箱子(bin),箱子中存放的是键值对。
10.加密方式
1.排序验签加密
//生成sign 主接口+ time+version+ tp + sign
+ (NSString *)getSignAndSignDict:(NSMutableDictionary *)dict
{
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:dict];
[dic setValue:QWVersion forKey:@"version"];
[dic setValue:[QWCommonFunc time] forKey:@"timeStamp"];
[dic setValue:QWPt forKey:@"pt"];
[dic setValue:QWImei forKey:@"imei"];
NSString *singstr = [self sortDicToString:dic];
return singstr;
}
//排序验签
+ (NSString *) sortDicToString:(NSMutableDictionary *)dic{
//排序
NSMutableArray *stringArray = [NSMutableArray arrayWithArray:dic.allKeys];
QWLog(@"%@",stringArray);
[stringArray sortUsingComparator: ^NSComparisonResult (NSString *str1, NSString *str2) {
return [str1 compare:str2];
}];
QWLog(@"%@",stringArray);
//验签
NSString *md5StrPre = @"";
for (int i = 0; i < [stringArray count]; i++) {
NSString *key = [stringArray objectAtIndex:i];
md5StrPre = [md5StrPre stringByAppendingString:[dic objectForKey:key]];
}
NSString *getKey = QWKey;
md5StrPre = [md5StrPre stringByAppendingString:getKey];
NSString *md5Str = [QWCommonFunc md5:md5StrPre];
return md5Str;
}
2.head头加密
let manager = AFHTTPSessionManager.init()
let secretKey = ""
let accessKey = ""
let t : String = BaseConfig.shared.t.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? " "
let randomStr : String = BaseConfig.shared.randomStr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? " "
let baseString = secretKey + randomStr + t
let sign = baseString.MD5()
manager.responseSerializer = AFJSONResponseSerializer.init(readingOptions: .mutableContainers)
manager.requestSerializer = AFJSONRequestSerializer.init(writingOptions: .prettyPrinted)
manager.requestSerializer.timeoutInterval = 7
manager.requestSerializer.setValue(sign, forHTTPHeaderField: "api-signature")
manager.requestSerializer.setValue(randomStr, forHTTPHeaderField: "api-echostr")
manager.requestSerializer.setValue(t, forHTTPHeaderField: "api-timestamp")
manager.requestSerializer.setValue(accessKey, forHTTPHeaderField: "api-access-key")
let contentTypes: Set = ["application/json", "text/json", "text/javascript","text/html", "application/x-javascript","audio/mpeg"]
manager.responseSerializer.acceptableContentTypes = contentTypes
3.AES加密
加密的过程: 字典 --> json字符串 --> base64加密后的字符串 --> AES加密后base64再加密 --> 输出加密后的字符串
解密的过程 : 与加密过程相反 ,输入参数 : base64String base64编码的字符串 ; key 密钥
AES的加密模式为 AES128 + ECB + NoPadding
网友评论