面试题答案
一键面试一、Cocoa 与 Cocoa Touch 框架差异
- 事件处理
- Cocoa(macOS):支持多种输入设备,如鼠标、键盘、触控板等。事件处理模型基于 responder chain(响应者链),视图(NSView)、窗口(NSWindow)、应用程序(NSApplication)等都可以成为响应者。例如,鼠标点击事件可以在视图或窗口级别处理。
- Cocoa Touch(iOS):主要针对触摸输入,事件处理围绕 touches(触摸点)展开。视图(UIView)是事件处理的核心,通过重写
touchesBegan:withEvent:
、touchesMoved:withEvent:
等方法来处理触摸事件。iOS 设备没有传统的鼠标和键盘,所以事件处理模型与 macOS 有较大不同。
- 应用生命周期管理
- Cocoa(macOS):应用启动后,会进入一个持续运行的状态,用户可以同时打开多个窗口,应用可以在后台保持活跃,例如在后台处理文件下载等任务。应用的终止通常由用户手动关闭或通过菜单选择退出。
- Cocoa Touch(iOS):iOS 应用通常只有一个窗口,应用启动后,展示主界面。iOS 应用有多种状态,如
Not Running
(未运行)、Inactive
(不活跃)、Active
(活跃)、Background
(后台)、Suspended
(挂起)。应用进入后台后,系统会对其进行挂起,限制其资源使用,以节省电量和系统资源。只有特定类型的任务(如音频播放、位置更新等)可以在后台继续运行。
- 后台运行机制
- Cocoa(macOS):应用可以在后台持续运行,执行各种任务,例如网络请求、文件处理等。应用可以获取系统资源,只要用户没有手动关闭应用或系统资源不足,应用可以长时间运行。
- Cocoa Touch(iOS):iOS 对后台运行有严格限制。应用进入后台后,通常会在短时间内被挂起。要在后台运行,应用需要在
Info.plist
中声明支持的后台模式,如App plays audio or streams audio/video using AirPlay
、App registers for location updates
等。并且后台任务有时间限制,一般在几分钟内完成,否则系统会终止应用。
二、通用代码适配策略
- 使用条件编译
通过
#ifdef
、#endif
等预处理指令,根据目标平台编译不同的代码。例如:
#ifdef TARGET_OS_IPHONE
// iOS 特定代码
#import <UIKit/UIKit.h>
@interface iOSViewController : UIViewController
@end
@implementation iOSViewController
// iOS 视图控制器实现
@end
#elif defined(TARGET_OS_MAC)
// macOS 特定代码
#import <Cocoa/Cocoa.h>
@interface MacViewController : NSViewController
@end
@implementation MacViewController
// macOS 视图控制器实现
@end
#endif
- 抽象通用逻辑 将通用的业务逻辑封装在独立的类或方法中,例如数据处理、网络请求等。这些通用代码可以在 iOS 和 macOS 项目中共享。例如:
// 通用数据模型类
@interface CommonDataModel : NSObject
@property (nonatomic, strong) NSString *data;
@end
@implementation CommonDataModel
@end
- 使用协议和代理 定义协议来抽象特定平台的行为,通过代理模式在不同平台实现协议。例如,定义一个显示提示框的协议:
@protocol AlertPresenterProtocol <NSObject>
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message;
@end
// iOS 实现
@interface iOSAlertPresenter : NSObject <AlertPresenterProtocol>
@end
@implementation iOSAlertPresenter
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:okAction];
// 获取当前视图控制器以显示 alert
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootViewController presentViewController:alertController animated:YES completion:nil];
}
@end
// macOS 实现
@interface MacAlertPresenter : NSObject <AlertPresenterProtocol>
@end
@implementation MacAlertPresenter
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:title];
[alert setInformativeText:message];
[alert addButtonWithTitle:@"OK"];
[alert runModal];
}
@end
在通用代码中,通过代理调用显示提示框的方法:
@interface CommonClass : NSObject
@property (nonatomic, weak) id<AlertPresenterProtocol> alertPresenter;
@end
@implementation CommonClass
- (void)someMethodThatNeedsToShowAlert {
[self.alertPresenter showAlertWithTitle:@"Alert" message:@"Some information"];
}
@end
三、可能面临的挑战及解决方案
- UI 适配挑战
- 挑战:iOS 和 macOS 的 UI 设计规范和控件差异较大。例如,iOS 使用
UIButton
,macOS 使用NSButton
,它们的属性和外观设置方式不同。同时,屏幕尺寸和分辨率的差异也需要考虑。 - 解决方案:使用 Auto Layout(iOS)和 Auto Layout / Stack Views(macOS)来处理布局。对于 UI 控件,可以通过前面提到的协议和代理方式,在不同平台实现特定的 UI 显示逻辑。例如,定义一个
ButtonProtocol
,在 iOS 和 macOS 分别实现UIButton
和NSButton
的创建和设置。
- 挑战:iOS 和 macOS 的 UI 设计规范和控件差异较大。例如,iOS 使用
- 性能优化挑战
- 挑战:iOS 设备资源相对有限,特别是在后台运行时,需要严格控制资源使用。而 macOS 应用虽然资源相对丰富,但也需要考虑多任务环境下的性能。
- 解决方案:在 iOS 中,优化内存使用,避免在后台执行长时间运行的任务,使用合适的后台模式。在 macOS 中,合理使用多线程和并发技术,优化资源分配,确保应用在多任务环境下的流畅运行。同时,在通用代码中编写高效的算法和数据结构,减少不必要的计算和内存开销。
- API 兼容性挑战
- 挑战:部分 API 在 iOS 和 macOS 上存在差异,甚至有些功能在一个平台存在,在另一个平台不存在。例如,iOS 的 Core Location 框架在 macOS 上的实现方式略有不同,并且 macOS 有一些与桌面相关的 API,iOS 没有。
- 解决方案:通过条件编译和封装通用接口来解决。对于存在差异的 API,在通用代码中定义抽象接口,在不同平台实现具体的 API 调用。例如,对于获取设备位置功能,定义一个
LocationService
协议,在 iOS 和 macOS 分别实现基于 Core Location 的具体位置获取逻辑。