Bo2SS

Bo2SS

The most comfortable reading time is (3) minutes?!

72nd National Day

Sorry, this series cannot be done. It is only to bring you the most fulfilling and detailed iOS learning experience. Reading the full text may take 3 hours, maybe 30 minutes, or even 3 minutes, or possibly 3 seconds. Afterwards, I will analyze how many readers only persisted for 3 seconds and continue to improve.

image

Welcome back to the iOS series introduced by "Xia Piao Piao" (3) — Common UI Components. This article mainly discusses the system architecture of iOS, important members of the UIKit components, their basic usage and features, and the UI anatomy of "Xia Piao Piao".

iOS System Architecture#

The system architecture of iOS is mainly divided into 4 layers, from bottom to top: Core OS, Core Services, Media, and Cocoa Touch, and above that constitutes an application.

image

Let's take a closer look at the main framework components of these 4 layers:

image

For beginners, the main focus is on: the "UIKit framework" of the Cocoa Touch layer + the "Foundation framework" of the Core Services layer. The following introduction comes from Apple's developer documentation:

  • UIKit: Build and manage graphical, event-driven user interfaces for your iOS or tvOS applications;
  • Foundation: Access basic data types, collections, and operating system services to define the foundational functionality of applications.

You can refer to Appendix 1 and Appendix 2 for their framework composition.

Regarding Foundation, the main focus is on the encapsulation of basic data types, which can be referred to in Objective_C Foundation Framework — Yii Bai Tutorial; about UIKit, it is our main character today❗️

UIKit#

Below is the inheritance relationship of important members of UIKit and their respective roles:

  • UIView — Displays content and provides interaction
    • UIImageView — Displays images
    • UILabel — Displays text
    • UIScrollView — Displays content larger than the screen (e.g., maps)
      • UITableView — Displays tabular content (e.g., phone book)

UIScrollView

UITableView

  • UIViewController — Manages a container for Views
    • UITabBarController — Manages the switching of multiple ViewControllers, tabbed switching method
    • UINavigationController — Manages the switching of multiple ViewControllers, push/pop switching method

UITabBarController

UINavigationController

After having a rough understanding of them, let's do a little exercise. What UIView and UIViewController are mainly included in the following two animations:

UITableView, UINavigationController...

UITableView, UITabBarController, UINavigationController...

If you can quickly identify their basic components, it indicates that you have a basic understanding of the roles of UIKit's foundational components.


So how should these basic components be used, and what are their features?

Let's first talk about two heavyweight members: UIView and UIViewController.

UIView#

Displays content and provides interaction

Basic Usage#

// 1)alloc: Allocate space for UIView; init: Initialize the object
UIView *view = [[UIView alloc] init];

// 2)Top-left point coordinates (100, 100), width and height 100 * 100
view.frame = CGRectMake(100, 100, 100, 100);

// + Set background color
view.backgroundColor = [UIColor redColor];  // Equivalent to UIColor.redColor

// 3)Add the newly defined view to the parent view
[self.view addSubview:view];

The following 3 steps are necessary. (❗️: Components inherited from UIView generally cannot do without these 3 steps)

1)Initialization: First, allocate space by calling the alloc class method of UIView, and initialize the object by calling the init method on the returned instance;

2)Set frame: That is, its top-left coordinates and width and height;

3)Add: Add the defined UIView object to a parent UIView object.

Features#

1)Stack structure management of subviews: It can add multiple subviews, with later added views displayed above earlier added ones, and the parent view can manage the view hierarchy of subviews.

image

From the above image, it is easy to see the order in which the two squares were added, red first and then green.

⚠️:

  • This feature may be one of the reasons for interaction failure, as for overlapping Views, the interaction of the upper layer will cause the interaction of the lower layer to fail.
  • Observant friends may wonder what self in the code represents; its view property is what will be mentioned next, the second heavyweight member.

As an object-oriented programming language, OC refers to the current object calling the method as self, and the type of self above is UIViewController.

UIViewController#

Manages a container for Views

If you understand the MVC pattern (see Appendix 3 at the end), the relationship with UIView becomes easy to understand: UIView is the V—View in MVC, and UIViewController is the C—Controller in MVC.

Basic Usage#

// 1)alloc: Allocate space for UIViewController; init: Initialize the object
UIViewController *viewController = [[UIViewController alloc] init];

// 2)Attach a certain view to the viewController's view
[viewController.view addSubview:someView];

1)Initialization

2)Add the UIView object to be managed

Features#

1)Acts as a container, containing a default view property of type UIView, which corresponds to the above❗️

image

RootView is a UIView object that comes with the UIViewController object.

2)Below is its lifecycle, where developers can choose to override and add some custom operations at appropriate times.

  • init -> loadView ->
  • viewDidLoad -> viewWillAppear -> viewDidAppear ->
  • viewWillDisappear -> viewDidDisappear ->
  • dealloc

image

  • This image is cited from quanqingyang's CSDN blog, which well illustrates the process of a UIViewController object from initialization 👉 loading view 👉 displaying view 👉 view disappearing 👉 unloading view 👉 destruction.
  • Beginners generally focus on init and viewDidLoad, adding some custom object initialization during init, and adding some custom subviews to self.view during viewDidLoad.

PS:

  • When creating a new project, a ViewController (.h header file and .m source file) is automatically generated, which serves as the root ViewController for the entire project by default.
  • Generally, we encapsulate some custom ViewControllers inherited from UIViewController, adding specific views and interaction logic inside.

Having discussed the two heavyweight members, let's take a short break and then look at the basic usage and characteristics of their descendants.

Descendants of UIView#

UIImageView#

Displays images

Basic Usage#

// 1)alloc: Allocate space for UIImageView; init: Initialize the object
UIImageView *imageView = [[UIImageView alloc] init];

// 2)Top-left point coordinates (100, 100), width and height 100 * 100
imageView.frame = CGRectMake(100, 100, 100, 100);

// 3)Set the image fill mode
imageView.contentMode = UIViewContentModeScaleAspectFill;

// 4)Define the specified image as a UIImage object and assign it to the imageView's image property
#define kImageName @"./ford.jpg"
imageView.image = [UIImage imageNamed:kImageName];

1)Initialization

2)Set frame

3)Set the image fill mode contentMode

Mainly includes the following:

image

The contentMode set in the above code is UIViewContentModeScaleAspectFill, corresponding to the second example in the above image, which is a common method.

4)Assign a value to the image property

All images must first be encapsulated into UIImage objects before being displayed through UIImageView.

Features#

1)Displays animated images: Assign an array of UIImage types to the animationImages property of UIImageView;

2)Related third-party library: SDWebImage, which can optimize the process of generating UIImage, generally used for fetching network images.

PS: SDWebImage: https://github.com/SDWebImage/SDWebImage

UILabel#

Displays text

Basic Usage#

// 1)Initialization
UILabel *summaryTabLabel = [[UILabel alloc] init];

// 2)Top-left point coordinates (100, 100), width and height 100 * 100
summaryTabLabel.frame = CGRectMake(100, 100, 100, 100);

// 3)Set text
summaryTabLabel.font = [UIFont systemFontOfSize:14];
summaryTabLabel.textAlignment = NSTextAlignmentCenter;
summaryTabLabel.textColor = [UIColor orangeColor];
[summaryTabLabel setText:@"Movie Summary"];

// PS: Set gesture
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(summaryTabTapAction)];
[summaryTabLabel addGestureRecognizer:tapGesture];
summaryTabLabel.userInteractionEnabled = YES;

1)Initialization

2)Set frame

3)Set text: font, alignment, text color, text content

PS: Set gesture

image

The tab bar (Movie Summary, Actor Information, More Information) in the details page of "Xia Piao Piao" is implemented based on UILabel, and adding click gestures to them allows them to behave like buttons.

⚠️: The interaction of UILabel objects is disabled by default, and the userInteractionEnabled property must be set to YES to enable it.

Features#

1)Multi-line display (as shown in the content of each tab in the above animation)

summaryTabLabel.numberOfLines = 0;  // Default is 1
[summaryTabLabel sizeToFit];

2)Text truncation methods: lineBreakMode property, such as breaking lines by characters, omitting parts in the middle, etc.
3)Display complex text: using NSAttributedString type, YYText (third-party library)

UIScrollView#

Displays content larger than the screen

Basic Usage#

// 1)Initialize and set visible range — frame
UIScrollView *detailScrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

// 2)Set scrolling range — contentSize
#define kScreenWidth UIScreen.mainScreen.bounds.size.width
#define kScreenHeight UIScreen.mainScreen.bounds.size.height
detailScrollView.contentSize = CGSizeMake(kScreenWidth * 3, kScreenHeight);

// PS: Whether to enable paging scroll
detailScrollView.pagingEnabled = YES;

1)Initialize and set frame

The frame is the visible range of this view, which can be set during initialization using initWithFrame instead of init.

The value assigned to self.view.frame in the above code is the frame of self.view, which you should know what it is from the beginning.

2)Set contentSize

contentSize is the scrolling range of this view, in other words, its entire range.

PS: Set whether scrolling is page-based: pagingEnabled property

image

Looking at the animation of "Xia Piao Piao", its contentSize is three times the screen width, with paging scrolling.

Features#

1)frame and contentSize

The former is the visible range, and the latter is the scrolling range.

These two are the most important properties when initializing UIScrollView, and incorrect settings may prevent scrolling.

2)setContentOffset method

[detailScrollView setContentOffset:CGPointMake(detailScrollView.bounds.size.width * 2, 0) animated:YES];

In the previous section, triggering the scrolling of UIScrollView by clicking the tab bar, in the event summaryTabTapAction corresponding to the UILabel click gesture, the setContentOffset method will be used.


Next is the youngest descendant of UIView, which inherits from UIScrollView and is also the most difficult to understand here.

UITableView : UIScrollView#

Displays tabular content

Basic Usage#

// 1)Initialize and set visible range — frame
UITableView *homeTableView = [[UITableView alloc] initWithFrame:self.view.bounds];

// 2)Specify dataSource and delegate (remember to add two protocols in the class declaration)
homeTableView.dataSource = self;
homeTableView.delegate = self;

// 3)Next, implement the methods in the protocols (@required must-implement items, @optional optional items)

1)Initialize and set frame

The frame refers to the visible range, similar to UIScrollView.

2)Specify the dataSource and delegate

dataSource and delegate are two protocols of UITableView. "Specifying the delegate" means letting "others" comply with this protocol to help do some things in the protocol, some of which are mandatory and some optional; it can be compared to labor agreements or rental contracts in our lives.

i. dataSource is responsible for the data source of the table, cell content, etc.;

ii. delegate is responsible for cell interaction, configuration, etc.

It should be clarified that the above code is written in the Controller, where self refers to an object of type UIViewController. This means that self complies with these two protocols and needs to implement the methods in the protocols.

3)Implement the methods in the protocols

i. dataSource

#pragma mark - UITableViewDataSource
// @required
// 1)Set the number of cells buffered in each Section
(NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section {
    return 3;
}

// 2)Render the content of each Cell
(UITableViewCell *)tableView:(UITableView *)tableView 
 cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 1. Find the cell corresponding to kCellId from the reuse pool (#define kCellId @"id1")
    //   [tableView dequeueReusableCellWithIdentifier:kCellId];
    // 1-2. If it does not exist, manually generate the corresponding cell and register it as kCellId
    //   [… reuseIdentifier:kCellId];
    // 2. Set cell data
    // 3. return cell
}

// @optional…

The dataSource protocol has 2 @required (must-implement) methods and several @optional (optional implementation) methods.
The first @required method is used to set the number of cells buffered in each Section, with return 3 indicating that only 3 pieces of data will be rendered. In actual use, it is generally determined by the number of data returned from a network request.

The second @required method is used to set the content rendered for each cell, as referenced in the code comments, generally divided into 3 steps:

  1. Find the cell corresponding to kCellId (custom cell identifier) from the reuse pool; if it does not exist, manually generate the corresponding cell and register its identifier in the reuse pool.
  2. Set the cell data.
  3. return cell.

PS: Regarding the reuse pool, it will be mentioned again shortly. UITableViewCell type inherits from UIView, and its basic usage and features are similar.

ii. delegate

#pragma mark - UITableViewDelegate
// @optional
// 1)Set the row height for each Cell
(CGFloat)tableView:(UITableView *)tableView 
 heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 100;

// 2)Set the event after clicking the Cell
(void)tableView:(UITableView *)tableView 
 didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // do Something after cell selected
}

// …

The delegate protocol has several @optional (optional implementation) methods, and the above lists two commonly used methods to be implemented.
The first @optional method is used to set the row height for each Cell.

The second @optional method is used to set the event after clicking a Cell, such as pushing another page.

Referring to the homepage of "Xia Piao Piao", feel the role of the above four methods to be implemented:

image

The number of movies in this movie table is determined by the data returned from the network request; the format of each Cell can be reused; the row height is fixed; the screen after clicking on a certain movie is left to your imagination.

Features#

1)UITableView only handles display; data, Cell, and interaction need to be provided by the developer.

i. dataSource: Data source, Cell content, etc.

ii. delegate: Cell interaction, configuration, etc.

2)Reuse pool

Since generating and destroying Cells is performance-intensive, the reuse pool mechanism was introduced, and its basic principle is as follows:

image

The underlying implementation of the reuse pool is based on a double-ended queue (dequeue). When scrolling up the screen, the cells above disappear and are automatically recycled by the system, placed into the reuse pool. When the cells below need to load, the system first searches the reuse pool for their unique identifier id. If found, it can be successfully reused; otherwise, a corresponding Cell is manually generated and registered in the reuse pool, binding the id.

From the following image, you can appreciate the essence of the reuse pool:

image

When scrolling up, the newly loaded Cell not only reuses the Cell's style but also reuses the green checkmark ✅ on the right.

In actual use, this can be somewhat amusing, so we generally set its data after reusing the Cell, as mentioned in the third step of basic usage; or override the prepareForReuse method to clear unnecessary data before each reuse of the Cell. (Note: prepareForReuse is a method of UITableViewCell)

At this point, we have a complete understanding of the composition of UITableView:

image

The demo of "Xia Piao Piao" we just displayed is only one section and does not set a Header and Footer.

In fact, a complete UITableView can refer to the above image, represented by the formula:

UITableView = tableHeaderView + n ✖️ Section + tableFooterView

Where Section = sectionHeader + n ✖️ UITableViewCell + sectionFooter


Finally, finally, have you persisted to this point? The "Descendants of UIView" check-in point, 💳 ding~

Below are the two promising children of UIViewController.

Children of UIViewController#

The common point of these two children is: they can manage the switching of multiple UIViewController objects, which sounds like the son can also manage multiple fathers~ 😛

The differences can be experienced by comparing the following introductions:

UITabBarController#

Basic Usage#

// 1)Initialization
UITabBarController *tabbarController = [[UITabBarController alloc] init];

// 2)Set the multiple Controllers to be managed (belonging to or inheriting from UIViewController)
[tabbarController setViewControllers:@[controller1, controller2, controller3]];

1)Initialization

2)Set the multiple Controllers to be managed

Set up at the beginning, and each Controller's type belongs to or inherits from UIViewController.

Now let's look at its demo:

image

This UITabBarController object manages three Controllers.

Features#

1)UITabBar, the switching bar at the bottom of the page:

Cited from "Geek Time"

The managed UIViewController objects modify the content of the corresponding Tab on the UITabBar themselves:

controller1.tabBarItem.title = @"News";
controller1.tabBarItem.image = [UIImage imageNamed:@"tab1.png"];

Such as icons, titles, etc.

UINavigationController#

Basic Usage#

// 1)Initialization and set the root Controller
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller1];

// 2)Push another Controller at the appropriate time
[navigationController pushViewController:controller4 animated:YES];

1)Initialization and set the root Controller
Only one needs to be set.

2)Then push another Controller at the appropriate time

For example, in "Xia Piao Piao", clicking on a certain movie on the homepage pushes the corresponding detail page Controller.

Now let's look at its demo:

image

When clicking the Show button, another Controller is pushed.

Features#

1)UINavigationBar, the navigation bar at the top of the page:

Cited from "Geek Time"

Similarly, the UIViewController objects modify the content of their page's UINavigationBar themselves:

controller4.navigationItem.title = @"Content";

Such as titles, etc., and can customize buttons on both sides.

2)Stack management: You can return to the previous level or return to the root view or a specified view.


Through the above discussion, do you understand the differences between UITabBarController and UINavigationController?

Next, let's extend two knowledge points, the favorite part of good students~ which can also deepen the understanding of the above content.

Extension 1: Common Page Switching Methods#

From the previous two types of Controllers, you can feel two different page switching methods. So what are the common page switching methods?

  1. tabs: You know who this refers to~
  2. push / pop: You know who this refers to~
  3. present / dismiss: Unlike the second method, it is generally used for switching between different business interfaces and can only return step by step.

image

  1. show (iOS 8.0+)

This method automatically selects the switching method based on the type of ViewController, as shown in the following image for the splitViewController's switching method:

image

Generally seen on iPad devices, such as the Taobao App.

Extension 2: Two Nesting Methods#

In actual use, UITabBarController and UINavigationController are often used together, and rather than a combination method, it is more of a nesting method.

Method One:

Cited from "Geek Time"

Method Two:

Cited from "Geek Time"

The most obvious difference between these two methods is whether the TabBar disappears during page switching.

But why does Apple officially recommend the first method? In summary, there are probably two points:

1)Higher freedom, each NavigationController is independent, and you can choose not to nest NavigationController;

2)Can achieve the same page switching effect as the second method by manually hiding the Tab bar.

Note: UI Rendering is on the Main Thread#

Today, we have extensively introduced the important components of UIKit, so don't forget this last reminder during their usage: UI rendering is all done on the main thread❗️

As for why? Here is an excerpt from Why UI Must Be Operated on the Main Thread — Juejin article.

1)UIKit is a thread-unsafe class. UI operations involve accessing various View object's properties, and if asynchronous operations are performed, there may be read-write issues; if locks are added, it will consume a lot of resources and slow down the running speed;

2)Only on the main thread can it respond to events. The starting point of the entire program, UIApplication, is initialized on the main thread, and all user events are passed on the main thread (such as clicks, drags), so UI can only respond to events on the main thread;

3)Ensure the synchronous update of images. In terms of rendering, since image rendering needs to be updated on the screen at a refresh rate of 60 frames, it cannot ensure that this processing can achieve synchronous updates in asynchronous situations on non-main threads.

Therefore, when performing UI rendering, be sure to pay attention to whether the current thread is the main thread!

UI Anatomy of "Xia Piao Piao"#

Now, let's take a look at what UIKit components are used in "Xia Piao Piao", directly showing the image!

image

👏 Did you gain a lot today? If you can reproduce the above image, then you must have a good grasp of UIKit! Feel free to leave a message to share your thoughts or any questions you may have.

See you next week#

Next week we will discuss debugging techniques in Xcode, so stay tuned.

Appendix#

1)Foundation

image

2)UIKit

image

By observing the parent classes of the components, you can easily locate the functionality of the components.

3)MVC Pattern

image

The MVC pattern is a software architectural pattern, and MVC is an acronym for three words: Model, View, and Controller:

1)Model is the data or information that the program needs to operate.

2)View is the interface provided to the user for operation, which is the shell of the program.

3)Controller is in between the above two, selecting data from the Model based on the commands input by the user in the View and performing corresponding operations to produce the final result.

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