通过遵循这些最佳实践,你将很大程度上避免许多麻烦
避免内存泄漏的最佳实践
- 避免大量的单例。具体来说,不要出现上帝对象(如职责特别多或状态信息特别多的对 象)。这是一个反模式,指代一种常见解决方案的设计模式,但很快产生了不良效果。 日志器、埋点服务和任务队列这样的辅助单例都是很不错的,但全局状态对象不可取。
- 对子对象使用 __strong。
- 对父对象使用 __weak。
- 对使引用图闭合的对象(如委托)使用 __weak。
- 对数值属性(NSInteger、SEL、CGFloat 等)而言,使用 assign 限定符。
- 对于块属性,使用 copy 限定符。
- 当声明使用NSError **参数的方法时,需要使用__autoreleasing,并要注意用正确的 语法:NSError * __autoreleasing *。
- 避免在块内直接引用外部的变量。在块外面将它们 weakify,并在块内再将它们 strongify。
- 进行必要清理时遵循以下准则:
- 销毁计时器
- 移除观察者(具体来说,移除对通知的注册)
- 解除回调(具体来说,将强引用的委托设置为 nil)
创建控制器时要遵循的最佳实践
- 保持视图控制器轻量。在 MVC 结构的应用中,控制器只是纽带,而不是存放所有业务 逻辑的地方。它甚至不属于模型。业务逻辑应该属于服务层或业务逻辑组件。将它放在那里。通过被称为行为委托或服务提供者的对象,视图控制器应该将服务组件绑定至视图,这 些行为委托或服务提供者的对象最好能被注入控制器
- 不要在视图控制器中编写动画逻辑。动画可以在独立的动画类中实现,该类接受视图作 为参数传入,这些视图就是用来运行动画的视图。然后,视图控制器会将动画添加至视 图或转场效果上。 有特殊用途的视图可以拥有自己的动画。例如,一个自定义的微调控制器会有它自己的 动画。
- 使用数据源和委托协议,将代码按照数据检索、数据更新和其他的业务逻辑进行分离。 视图控制器只能用来选择正确的视图,并将它们连接到供应源。
- 视图控制器响应来自视图的事件,如按钮点击事件或列表单元格的选择事件,然后将它 们连接至数据接收器。
- 视图控制器响应来自操作系统的 UI 相关事件,如方向变化或低内存警告。这可能会触 发视图的重新布局。
- 不要编写自定义的 init 代码。 为什么呢?因为如果视图控制器被重新切换至 XIB 或故 事板,那 init 方法永远都不会被调用。
- 不要在视图控制器中使用代码手工布局 UI,也不要在视图控制器中实现全部的 UI、视 图创建和视图布局逻辑等操作。使用 nibs 或者故事板。 手工布局代码不会持续很久,因为应用在不断增长,并且设计也在改变。在重新设计方 面,使用 Interface Builder 比根据像素坐标来手动编写代码更快。 此外,应用可能会在不同大小和形状的设备上运行。要想适应所有的形状,处理方向变化时的旋转操作,以及与每两三年就会变化的设计范例保持一致,通过扩展自定义代码来实现是比较难做到的。同样,如果某一设计被分在独立的 nibs 和故事板,你就可以比较灵活地运行 A/B 测试, 因为在不同的约束之间很容易选择最终需要的。
- 比较好的方式是,创建一个实现了公共设置的基类视图控制器,其他视图控制器从这里 继承就好。
这种技术并非一直可用,因为有时可能需要在应用的不同部分继承不同的视图控制器。 例如,在联系人列表中应该使用 UITableViewController,在用户配置文件中应该选择 UIViewController。
但是,如果有多个地方都需要在 UIWebView 中展示内容,那基类视图控制器会是一个不 错的选择。如果需要显示含有隐私策略的 URL 或条款和条件页面,那么你是没必要继 承的。但是,如果需要显示用户分享的图片或者视频(在信息应用中),你可以创建子 类,在子类中实现自定义浏览器或对重写的东西进行控制。 - 在各视图控制器之间,使用 category 创建可复用的代码。如果父视图控制器不能满足 使用(例如,在应用中需要不同种类的视图控制器),那就创建 category,并在 category 中加上自定义的方法或属性。 如此一来,你就不会被限制只能使用预定义的基类,同时还能得到复用带来的好处。
高效使用viewController的生命周期
- 无需多说,不要重写 loadView。
- 将 viewDidLoad 作为最后的检查点,查看来自数据源的数据是否可用。如果可用,则更
新 UI 元素。如果每次都需要展示最新的信息,那么就使用 viewWillAppear: 更新 UI 元素。
例如,在某一个消息应用中,如果在聊天会话中观看完共享视频后返回信息列表,那么用户必然希望看到最新的信息。但在新闻应用中,你可能不希望立即刷新列表,以免用户找不到上下文。在后一种情况 下,列表视图控制器一般会监听来自数据源的事件,同时,应尽量精准、尽量少地更新 文章列表。 - 在 viewDidAppear: 中开始动画。如果有视频等流式内容,那么就可以开始播放了。订 阅应用事件来检测动画 / 视频或其他持续更新视频的处理是应该继续还是停止。 不推荐在该方法中用最新的数据更新 UI。如果你这样做了,最终的效果是,在过渡动 画完成之后,用户会过渡至旧的 UI,然后产生更新。这个体验不是很友好。话虽如此,但在一些使用案例中,你不得不在 viewDidAppear: 中执行 UI 更新。如果用 户体验尚可接受,那就勉强这样吧。
- 使用 viewWillDisappear: 来暂停或停止动画。同样,不要做其他多余的操作。
- 使用 viewDidDisappear:销毁内存中的复杂数据结构。也可以在这里注销与视图控制器绑定的数据源通知,以及与动画、数据源、UI 更新有 关的应用事件通知中心。
- 如果其他措施都不能优化载入时间,那么你可以在应用中增加一个精巧的动 画。如此一来,你将会有数十秒的额外时间来完成任务,让用户在使用应用 时不会有明显的延迟。需要注意的是,长时间的动画会惹恼用户,可能导致 用户流失。这应该作为最后的方案,需要慎用。
参考文献:“High Performance iOS Apps by Gaurav Vaish (O’Reilly). Copyright 2016 Gaurav Vaish, 978-1-491-91100-6.”
网友评论