The Things about iOS App Development series takes a broader view, not just of the implementation of a specific feature or interface, but of the combination
Netease cloud letterFrom the perspective of how to optimize the existing code, in-depth analysis of how to create a more appropriate specification and framework for iOS APP development.

Recommended reading

Things about iOS App Development # 1: How do you build the right specs

A proper framework is not a silver bullet, and it seems to me that the problem with a framework has never been that the project can proceed correctly if it has one. A good framework can do just that: reduce the complexity of common problems and reduce the likelihood of errors. In my opinion, a good iOS App framework should have the following characteristics:

Define a clear hierarchy

Horizontally, the modules are independent of each other and communicate through a limited number of interfaces. Ideally, all modules except the core module are pluggable. Vertically, the dependency relationship between different levels is clear, and there is almost no reverse dependency.

Horizontal modules are typically dependent on business requirements and are often defined as various Services or managers. It is a good practice to have a unified Service manager responsible for loading, unloading, listening and distributing app-level notifications to the corresponding Service, such as switching between front and back, receiving memory warnings, etc. On the one hand, it is easy to achieve the pluggability of the modules mentioned above, on the other hand, it ensures the consistency of common feature processing. In this aspect, wechat has done a good job. Basically, all modules are inherited from MMService and managed by MMServiceCenter. Of course, you can also find some management disorders in the dump headers. For example, some viewControllers inherit from MMService.

Basically, there is no big difference between apps in vertical hierarchy, which can be divided into three levels:

  • Presentation Layer, which manages the UI and UIViewController.
  • The Logical Layer (Business/Service Layer) is responsible for the definition and forwarding of logical data and serves as a link between the preceding and the following.
  • Data Access Layer, responsible for specific API construction, network requests, Data persistence, etc.

Depending on the complexity of the business logic, each layer uses a single or multi-layer structure. Taking data access layer as an example, it can be subdivided into network layer and persistence layer. Generally speaking, the presentation layer (UIView and UIViewController) directly uses the Model provided by the logic layer to display, but in some scenarios, different models are often required to have the same interface display (such as our App Easy Message, session interface, favorites interface, The ask function all requires image presentation, but the Model definitions under these three modules are not the same), which requires additional ViewModel layers to glue the presentation layer to the logical Model.

Follow SOLID principles and be careful with various design patterns

This is a cliche, not unique to iOS development, and could go on for days and nights.

Define your own UI base classes: UIView, UIViewController, UITableviewCell

The advantage of this is that all child views, controllers, and cells can easily inherit the common behavior and style of the base class. But it also introduces great management risk: members of the group will always be tempted to cram various features that are not universally applicable into the base class, resulting in infinite expansion of the base class’s responsibilities. Large base classes not only make it harder for group members to understand the code, they also make it harder to troubleshoot problems when they occur. In this regard, wechat’s UIViewController base class design is an extreme failure: MMUIViewController has hundreds of lines of bareheaded files.

Provide handy utility classes

Useful utility classes often become an integral part of the framework, providing quick and easy solutions to local problems without introducing too much complexity. NSTimer’s retain cycle is an easy pit to fall into, so providing a Block or weak delegate-based NSTimer wrapper is a good option. Use KVO to make mismatched calls to add and remove, so introduce THObserversAndBinders or FB KVOContorller. When some core modules need to be dependent on more than one module, the introduction of xMPp-like GCDMulticastDelegate is a convenient way to decouple.

Good example

In the early days of using C++, I often wondered how to limit and avoid bugs at the API level. For example, tasks thrown into the thread pool must be heap-allocated objects, so how do we enforce that the incoming pointer points to the heap address instead of the stack address? Most of the time, this kind of silly problem has no solution, and sometimes the solution is a very awkward solution. Now I believe more in the possibility of broken Windows: do a good job and everything will fall into place.

Review the first article in this series, and we welcome your comments.

Want to get more product dry goods, technical dry goods, welcome to pay attention to netease yunxin blog ~


NeteaseYunXin is a PaaS service product combining 18 years of NETEASE’S IM and audio and video technologies. It is a communication and video cloud service based on netease’s core technology architecture, which is stable, easy to use and has comprehensive functions. It is committed to providing the world’s leading technical capabilities and scene-oriented solutions. By integrating the client SDK and OPEN API, developers can quickly realize functions including IM, audio and video calls, live broadcast, on-demand, interactive whiteboard, and SMS.