贝壳
一面:
1.SDK体积优化,从多大优化到了多大,为什么减少Masony的使用会减少包大小
2.加载速度优化,两套网络请求的问题
3.上传视频需要注意什么?视频很大,分片,内存占用
4.自动释放池,什么时候会加 autorelease,一个方法里,alloc一个对象,这个对象加了autorelease吗?如果这个方法返回了这个对象呢?自动释放池能嵌套吗?
5.循环引用,block什么时候循环引用,block用到了_xxx成员变量,会循环引用吗?成员变量会编译成什么 self ->
6.NSTimer的循环引用,为什么?
7.多线程:A/B/C并发,请求完成后执行其他任务
二面:
1.通用化技术提升迭代效率指的什么?卡片等是什么实现的
2.多线程:A -> B C -> D B依赖A、D依赖C,都完成后执行E
3.代理和block怎么选型?
4.页面传值一对多怎么实现?对象加到数组里,这个对象的引用计数增加了吗?weak呢?
5.SDWebImage原理,解码是在什么时候做的?一张图片加载到界面的过程,大图加载
6.设计:多个弹窗依次弹出,有优先级
三面:
1.iOS中遇到过的不易解决的问题,怎么解决的?
2.A -> B -> C 用路由的方式反向传值,什么是路由?什么时候注册?参数是什么类型?
3.autoreleasePool和Runloop的关系
4.mach-o了解吗?
参考答案
一面:
1.SDK体积优化,从多大优化到了多大,为什么减少Masony的使用会减少包大小
2.加载速度优化,两套网络请求的问题
3.上传视频需要注意什么?视频很大,分片,内存占用
在iOS开发中,网络请求上传视频是一个常见的需求,尤其是当视频文件较大时,更需要注意一系列的技术细节和优化手段以确保上传过程的稳定性、效率和用户体验。以下是一些关键的注意事项和优化手段:
注意事项
- 文件大小检测:
- 在上传前,先检查视频文件的大小,避免上传过大的文件导致内存溢出或上传时间过长。
- 网络状态检测:
- 检测用户的网络状态(如Wi-Fi、4G/5G等),根据网络状况调整上传策略,如在网络较差时暂停上传或提示用户。
- 用户反馈:
- 提供清晰的上传进度反馈,让用户了解上传的当前状态和预计剩余时间。
- 权限检查:
- 确保应用已获取必要的权限,如访问相册或相机权限,以便读取视频文件。
优化手段
- 视频压缩:
- 在上传前对视频进行压缩,减小文件大小,从而减少上传时间和占用的网络带宽。可以使用如FFmpeg等库进行视频转码和压缩。
- 分片上传:
- 将大视频文件分割成多个较小的片段,并行上传这些片段。这样可以显著提高上传速度,并降低因网络问题导致上传失败的风险。当所有片段都上传完成后,服务器端可以将这些片段合并成完整的视频。
- 断点续传:
- 支持断点续传功能,即在网络中断或应用退出等情况下,能在下次上传时从上次中断的地方继续上传,而不是重新开始上传整个视频。
- 适当设置HTTP头部:
- 设置合适的Content-Type,并确保HTTP头部中的其他字段(如Content-Length)正确无误。对于分片上传,每个片段请求都应有对应的头部信息。
- 使用合适的网络库:
- 利用成熟的网络库(如AFNetworking、URLSession等)来简化网络请求的代码量,并利用这些库提供的优化功能来提高上传效率。
- 缓存策略:
- 对于已上传的视频或片段,可以在本地缓存其状态和信息,以便在网络恢复或应用重启时快速恢复上传状态。
- 后台上传:
- 利用iOS的后台任务功能,在应用进入后台时继续上传视频,不影响用户的其他操作。
- 错误处理和重试机制:
- 实现完善的错误处理逻辑,当上传失败时,根据错误类型进行重试或提示用户。可以设置合理的重试次数和重试间隔。
综上所述,iOS网络请求上传视频时需要注意多个方面,并通过一系列优化手段来提高上传的效率和稳定性。这些优化手段不仅有助于提升用户体验,还能降低因网络问题导致的数据丢失风险。
4.自动释放池,什么时候会加 autorelease,一个方法里,alloc一个对象,这个对象加了autorelease吗?如果这个方法返回了这个对象呢?自动释放池能嵌套吗?
5.循环引用,block什么时候循环引用,block用到了_xxx成员变量,会循环引用吗?成员变量会编译成什么 self ->
6.NSTimer的循环引用,为什么?
7.多线程:A/B/C并发,请求完成后执行其他任务
二面:
1.通用化技术提升迭代效率指的什么?卡片等是什么实现的
2.多线程:A -> B C -> D B依赖A、D依赖C,都完成后执行E
3.代理和block怎么选型?
4.页面传值一对多怎么实现?对象加到数组里,这个对象的引用计数增加了吗?weak呢?
5.SDWebImage原理,解码是在什么时候做的?一张图片加载到界面的过程,大图加载
6.设计:多个弹窗依次弹出,有优先级
三面:
1.iOS中遇到过的不易解决的问题,怎么解决的?
2.A -> B -> C 用路由的方式反向传值,什么是路由?什么时候注册?参数是什么类型?
在iOS应用中通过路由机制进行页面导航和数据传递时,有时需要将数据从一个页面传递回到之前的页面。可以通过闭包(Block)来实现这种反向传值。下面是一个详细的示例,展示了如何通过路由机制进行反向传值。
示例:通过路由进行反向传值
假设我们有三个页面:A -> B -> C,并希望在C页面完成某些操作后将数据传回A页面。
1. 定义路由管理器
首先,我们需要一个路由管理器来管理导航和数据传递。我们将使用一个单例类Router
来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #import <Foundation/Foundation.h> #import <UIKit/UIKit.h>
typedef void (^CompletionHandler)(id data);
@interface Router : NSObject
+ (instancetype)sharedInstance;
- (void)registerPath:(NSString *)path forClass:(Class)className; - (void)openPath:(NSString *)path withParams:(NSDictionary *)params completionHandler:(CompletionHandler)completionHandler;
@end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #import "Router.h"
@interface Router () @property (nonatomic, strong) NSMutableDictionary *routeMap; @end
@implementation Router
+ (instancetype)sharedInstance { static Router *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[Router alloc] init]; }); return instance; }
- (instancetype)init { self = [super init]; if (self) { _routeMap = [NSMutableDictionary dictionary]; } return self; }
- (void)registerPath:(NSString *)path forClass:(Class)className { self.routeMap[path] = className; }
- (void)openPath:(NSString *)path withParams:(NSDictionary *)params completionHandler:(CompletionHandler)completionHandler { Class className = self.routeMap[path]; if (className) { UIViewController *viewController = [[className alloc] init]; if ([viewController isKindOfClass:[UIViewController class]]) { if (completionHandler) { [viewController setValue:completionHandler forKey:@"completionHandler"]; } [viewController setValuesForKeysWithDictionary:params]; [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:viewController animated:YES completion:nil]; } } else { NSLog(@"No route found for path: %@", path); } }
@end
|
2. 定义页面C
在C页面中定义一个回调Block,用于传递数据。
1 2 3 4 5 6
| #import <UIKit/UIKit.h>
@interface CViewController : UIViewController @property (nonatomic, copy) void (^completionHandler)(id data); @end
|
在C页面完成操作时调用回调Block。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #import "CViewController.h"
@implementation CViewController
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(100, 100, 100, 50); [button setTitle:@"Send Data" forState:UIControlStateNormal]; [button addTarget:self action:@selector(sendData) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; }
- (void)sendData { NSString *data = @"Some data from C"; if (self.completionHandler) { self.completionHandler(data); } [self dismissViewControllerAnimated:YES completion:nil]; }
@end
|
3. 注册路由
在AppDelegate中注册路由。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #import "AppDelegate.h" #import "Router.h" #import "AViewController.h" #import "BViewController.h" #import "CViewController.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[Router sharedInstance] registerPath:@"a" forClass:[AViewController class]]; [[Router sharedInstance] registerPath:@"b" forClass:[BViewController class]]; [[Router sharedInstance] registerPath:@"c" forClass:[CViewController class]]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.rootViewController = [[AViewController alloc] init]; [self.window makeKeyAndVisible]; return YES; }
|
4. 使用路由
在A页面中导航到C页面并处理回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #import "AViewController.h" #import "Router.h"
@implementation AViewController
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(100, 100, 100, 50); [button setTitle:@"Go to C" forState:UIControlStateNormal]; [button addTarget:self action:@selector(openCViewController) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; }
- (void)openCViewController { [[Router sharedInstance] openPath:@"c" withParams:@{} completionHandler:^(id data) { NSLog(@"Received data: %@", data); }]; }
@end
|
总结
通过以上步骤,你可以实现页面间的数据传递和反向传值。路由管理器负责管理页面的导航和数据传递,页面C通过回调Block将数据传回A页面。这种方法不仅简化了页面间的数据传递,还保持了代码的清晰和可维护性。
3.autoreleasePool和Runloop的关系
4.mach-o了解吗?