Bo2SS

Bo2SS

2 Application Development (Part 1)

It's been a while since "A Comprehensive Overview of the iOS Knowledge System," and now we are starting a new chapter—Application Development. In this chapter, we will discuss GUI frameworks, reactive frameworks, animations, A/B testing, and message buses in iOS development.

image

Previous Recommendations:

If you missed the first chapter—Fundamentals, you can jump to it here:

“A Comprehensive Overview of the iOS Knowledge System” Fundamentals (Part 1)

“A Comprehensive Overview of the iOS Knowledge System” Fundamentals (Part 2)

“A Comprehensive Overview of the iOS Knowledge System” Fundamentals (Part 3)

“A Comprehensive Overview of the iOS Knowledge System” Fundamentals (Best Learning Path)

21 | What GUI frameworks can be used for iOS development besides Cocoa?#

To optimize the app's startup speed, in addition to addressing the main thread, we can also consider optimizations on the GUI (Graphical User Interface).

The currently popular GUI frameworks besides Cocoa Touch include Texture (formerly AsyncDisplayKit), WebKit, React Native (Facebook), and Flutter (Google). Their comparisons are as follows:

GUI FrameworkCocoa TouchTextureWebKitReact NativeFlutter
Platform supportiOSiOSiOS, AndroidiOS, AndroidiOS, Android
Programming languageOC, SwiftOC, SwiftJavaScriptJavaScriptDart
Render engineCoreAnimationCoreAnimationWebCoreNativeSkia
Layout methodFrame, Auto LayoutFlexBoxFrame, FlexBoxFrame, FlexBoxFrame, FlexBox, LayoutWidgets
  • FlexBox layout allows iOS developers to utilize advanced W3C standard responsive layouts. The newly introduced UIStackView layout method in iOS is also designed based on the FlexBox layout concept. Cocoa Touch framework itself does not support FlexBox layout, but it can be used through Facebook's Yoga library.

  • The basic unit of the Texture framework is the ASDisplayNode, which is an abstraction based on UIView. Compared to UIView, ASDisplayNode is thread-safe and can be instantiated and configured in parallel on background threads. Because Texture uses asynchronous node calculations, it can improve the responsiveness of the main thread.

  • In iOS development, the UIWebView and WKWebView controls we commonly use are both based on the WebKit framework. The author has previously written a blog post “In-depth Analysis of WebKit” that details its principles.

  • The rendering-related introductions for React Native and Flutter frameworks will be elaborated in the upcoming native and frontend collaboration chapter.

What is in a GUI framework?#

Controls, rendering trees, rendering layer trees.

  • Controls mainly handle the storage and updating of interface element data;

  • The rendering tree is an abstract tree structure that mainly records the relationships between controls;

  • The rendering layer tree consists of rendering layer objects, which are created based on the optimization conditions of the GUI framework. It records which controls are included, and combined with the rendering tree layout, it can generate a Bitmap for the GPU to render.

The relationship diagram among them is as follows:

Relationship among controls, rendering trees, and rendering layer trees—“Geek Time”

Others:

  • The slow display of web pages using WebKit is not due to its rendering performance being inferior to other frameworks, but mainly due to the way CSS and JavaScript resources are loaded. Additionally, the need to be compatible with older versions when parsing HTML, CSS, and JavaScript, as well as JavaScript type inference failures requiring reprocessing, and the lack of a reuse mechanism for lists, also contribute to the overall performance of the WebKit framework being less optimal than other frameworks.

  • Flutter was originally based on the Chrome browser engine. Later, considering Flutter's performance, Google removed its support for HTML, CSS, and JavaScript, opting instead for its own Dart language to shed historical baggage. Specific details can be found in the interview video with Flutter founder Eric—Zhihu.

Rendering Process#

The rendering technology in GUI frameworks has remained stable, generally going through three stages: layout, rendering, and composition.

  • Layout stage: Mainly calculates the size and position of controls based on the rendering tree.

  • Rendering stage: Primarily uses graphic functions to calculate the content of the interface. Generally, for 2D plane rendering, CPU calculations are used, while GPU calculations are used for 3D space rendering.

  • Composition stage: Mainly merges layers to save display memory.

Asynchronous drawing of Node in Texture:

For iOS developers who wish to significantly enhance user interaction experiences, Texture offers a low switching cost and substantial performance gains.

Its advantages are:

  1. Developed thread-safe ASDisplayNode;

  2. Can coexist well with UIView.

Asynchronous drawing principle:

ASDisplayLayer (a wrapper for CALayer) is the starting point of the entire drawing process. Drawing events are first set in the displayBlock, and then ASDisplayNode (which replaces the delegate in CALayer) calls the displayBlock for asynchronous drawing. Since the displayBlock uses thread-safe Core Graphics, it can be executed asynchronously on a background thread.

22 | A Detailed Look at the Evolution of iOS Reactive Frameworks#

Introduction to Reactive Frameworks#

Definition: Frameworks that support the reactive programming paradigm.

Characteristics: Using reactive frameworks allows for the propagation of data changes through data streams during programming. The computational model responding to this data stream will automatically compute new values and pass them to the next responding computational model through the data stream, repeating this process until there are no more responders.

Current Status: iOS reactive frameworks include ReactiveCocoa (abbreviated as RAC) and RxSwift, but neither has gained popularity until the frontend introduced React.js, after which reactive thinking flourished.

So why hasn't ReactiveCocoa gained traction in iOS native development?

Looking at the Problem#

The thinking behind the ReactiveCocoa framework is fundamentally consistent with that of React.js. So let's see what the React.js framework has done. The key lies in the addition of the Virtual Document Object Model (Virtual DOM).

The underlying structure of the React.js framework includes a Virtual DOM, which is bound to the state of page components and has a mapping and transformation relationship with the DOM (Document Object Model). Its rendering principle is illustrated in the following diagram:

Rendering Principle of React.js Framework—“Geek Time”

It can be seen that:

  • The React.js framework first operates on the Virtual DOM, which does not directly render the DOM. Instead, after completing the Diff calculation to obtain all the actual changed nodes, it performs a DOM operation and then renders as a whole. The Virtual DOM acts as a cache between JavaScript and the DOM.

  • Unlike JavaScript, which re-renders everything every time it operates on the DOM, leading to significant performance loss.


Returning to the question: Why hasn't ReactiveCocoa gained traction in iOS native development?

For the frontend, the structure of the DOM tree is very complex, and a complete change to the DOM tree can lead to serious performance issues, which the Virtual DOM can effectively resolve.

However, for iOS native Cocoa Touch framework:

  • This performance issue does not exist, as its interface node tree structure is much simpler than the DOM tree;

  • Moreover, its rendering mechanism differs from that of the frontend. Cocoa Touch does not immediately re-render the entire view node tree when updating the view. Instead, it marks the view as needing a layout through the setNeedsLayout method, and only when the drawing cycle reaches this view node does it call the layoutSubviews method for re-layout, followed by rendering.

Thus, the ReactiveCocoa framework has not brought better performance to iOS apps. When a framework is optional and does not provide significant benefits, teams generally have no reason to adopt it.


Others: There are many aspects of ReactiveCocoa that are worth learning from, such as:

  • Upper-level interface design philosophy: Functional reactive programming can be implemented through callbacks and KVO;

  • Use of macros: Refer to Reactive Cocoa Tutorial: Amazing Macros——sunnyxx.

23 | How to Create Stunning Animation Effects?#

Industry Pain Points#

  • Manually writing animation code is very complex, and many animation detail adjustments require constant communication and refinement with animation designers;

  • Developers across iOS, Android, and Web platforms need to maintain their own animation code.

The question arises: Is there a way to isolate animation production from programming development, allowing specialists to focus on their tasks while maintaining consistent animation effects across platforms?

Lottie#

Yes, that is the Lottie framework, an open-source animation framework by Airbnb.

Usage Steps:

  1. Animation designers create animations using After Effects and then export the animations as JSON files using the Bodymovin plugin;

  2. Developers use Lottie to load and render this JSON file, automatically converting it into the corresponding animation code.


Implementation Principle:

Lottie does the following in iOS:

  1. Maps the contents of the JSON file (the intermediate medium generated by After Effects) to the properties of classes such as LayerModel, Keyframe, ShapeItem, DashElement, Marker, Mask, and Transform in iOS, saving them;

  2. Renders them through CoreAnimation.

Thus, Lottie automates the process of transforming animation design files into development code, delegating the task of setting properties like LayerModel to the JSON file and Lottie mapping rules.


💡Tips:

  1. A workflow like Lottie may be the trend of the future, just like the current development trend in iOS, where more and more business logic no longer needs to be implemented entirely in Objective-C or Swift, but can be described using JavaScript or DSL, or even tools, and then the code describing the business can be converted into an intermediate code, such as JSON, which different platforms can parse and process to execute the business logic described by the intermediate code.

  2. For detailed explanations and usage example code of Lottie, refer to the official Lottie iOS tutorial. Lottie supports not only physical effects but also transition animations between pages.

  3. Developers without the cooperation of animation designers can check out LottieFiles, a platform for animation designers to share their works, where each animation effect's JSON file can be downloaded for use.

Author: Okiri George

24 | A/B Testing: A Tool for Validating Decision Effects#

Definition of A/B Testing#

A/B testing, also known as bucket testing or split testing, refers to testing two versions A and B of a variable to observe different user reactions, thereby determining which version is more effective, similar to the dual-sample hypothesis testing used in statistics.

In simple terms, A/B testing checks which version of a feature receives better user feedback when different app users use different versions.

A/B Testing in App Development:

In app version iterations, we can understand the old version as version A in A/B testing and the new version as version B. Both versions coexist, and the B version initially places a small portion of users in the B testing bucket, gradually expanding the user range. By analyzing the data from versions A and B, we can see which version is closer to the desired goal and ultimately decide which version to use.

Overall, A/B testing is a data-driven, reversible gray scheme that is objective, safe, and low-risk, serving as a mature trial-and-error mechanism.

A/B Testing Framework Design#

An A/B testing framework mainly includes three parts, as illustrated in the structure diagram below:

Structure Diagram of A/B Testing Scheme—“Geek Time”

  • Strategy service, which provides strategies for decision-makers, including decision-making processes and strategy dimensions.

    • Generally provided by the server, allowing the server to allocate testing buckets based on the distribution of user groups at any time.
  • A/B testing SDK, integrated into the client, used to control the upper-level business to follow different strategies.

    • Recommended: SkyLab, authored by Mattt, who is also the author of the well-known AFNetworking and Alamofire networking libraries. This library uses blocks to handle the differences between A/B versions in its interface design, making it highly usable and worth learning.

    • Effectiveness mechanism: If a strategy is effective in only one place, a hot start effectiveness mechanism can be used; if a strategy is effective in multiple places, it is better to use a cold start effectiveness mechanism.

  • Log system, responsible for feeding back strategy results for analysts to analyze the results of different strategy executions.

    • Generally provided by the server.

25 | How to Build a Bottom-Level Publish and Subscribe Event Bus?#

Definition of Event Bus#

An event bus is an implementation of the publish and subscribe design pattern, which can decouple one-to-one and one-to-many relationships between components through publishing and subscribing.

This design pattern is particularly suitable for the data layer to inform UI layer subscribers of data through asynchronous publishing, allowing the UI layer and data layer to remain uncoupled, so that restructuring the data layer or UI layer does not affect the business layer.

  • Block and Delegate. Suitable only for one-to-one patterns; if continuous asynchronous publishing to the next data subscriber is needed (where messages have causal relationships), callback nesting with other callbacks may occur.

  • KVO and NSNotificationCenter. They support one-to-many patterns. However, using KVO is strongly dependent on properties; as soon as a property is updated, it will publish to all observers, making the corresponding relationship too flexible and difficult to manage and maintain. Similarly, using NSNotificationCenter has similar issues, as it maintains the relationship between publishers and subscribers through strings, which not only reduces readability but also faces difficulties in management and maintenance like KVO.


Q: Are there any good third-party libraries to handle the event bus?

Actually, the previously mentioned reactive third-party libraries ReactiveCocoa and RxSwift both support event buses, but these two libraries focus more on reactive programming, with event buses being just a small part of them. Therefore, using them would be somewhat overkill.

Currently, there is a pattern in the frontend field called Promise, which is a unified rule set specifically for asynchronous data operations.

Promise#

Essentially, this pattern saves asynchronous data operations through Promise objects, while providing a unified interface for handling asynchronous data operation events.

Promise objects have three states:

  1. pending: The asynchronous event is waiting to be processed;

  2. fulfilled: The asynchronous event has successfully completed;

  3. rejected: The asynchronous event did not complete successfully.


There are also two important methods: then and catch.

Every time a Promise object executes the then or catch method, it returns the previous Promise object, and the state of that Promise object changes based on the result of the asynchronous operation.

  • then: Executes the then method corresponding to the subscription operation, and the Promise object triggers the then method corresponding to the publishing operation. The then method returns the Promise object after execution and can continue to synchronously execute multiple then methods, thus achieving one publishing operation corresponding to multiple subscription events.

  • catch: If the Promise object returned after executing the then method is in the rejected state, the program will directly execute the catch method.


Q: How to use the Promise pattern in iOS?

Introduce PromiseKit (developed by Max Howell, the author of Homebrew).

Additionally, PromiseKit provides extensions for Apple's APIs, such as UIKit, Foundation, CoreLocation, QuartzCore, CloudKit, etc., and even supports third-party frameworks like Alamofire. For specifics, refer to PromiseKit Organization.

By using a simple, clear, and standardized Promise interface to connect asynchronous data retrieval, business logic, and interfaces, future maintenance or restructuring will be much easier. Give it a try!

That's all for today's sharing! Next time we will enter the second part of "A Comprehensive Overview of the iOS Knowledge System" on Application Development, covering topics such as JSON processing, layout frameworks, rich text, TDD/BDD, and coding standards. Don't forget to follow along, and see you next time!

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.