mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 12:27:15 +00:00
Add 3 chapter notes and update chapter index
This commit is contained in:
88
Chapter1 - iOS/1.1.md
Normal file
88
Chapter1 - iOS/1.1.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# Image Assets Optimization for Project Size
|
||||||
|
|
||||||
|
> A small iOS project with many features can grow large in size. Under an Xcode project, image assets can take up a lot of space, and if an app needs a one-click skin/theme change, imagine how many images that requires. Each set of images also needs 1x, 2x, 3x, etc.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
IconFont technology originated in the web field from Web Font technology. Over time, web design became more beautiful. But system-installed fonts on computers could no longer satisfy designers, so Web Font technology was born. An English character font set is not large; by downloading fonts over the network, webpages can be rendered. With Web Font technology, designers gained much more freedom.
|
||||||
|
|
||||||
|
In web design, icons need to adapt to multiple resolutions, and each icon would require a separate network request. Someone thought to use the Web Font approach to solve both problems: make vector icons into a font, so a single network request suffices and the icons scale cleanly. Another way to solve this is using sprite images.
|
||||||
|
|
||||||
|
The web community has used IconFont-like techniques for years—when I first encountered Bootstrap in 2015, Font Awesome was very popular. Recently IconFont technology has been applied to iOS image assets. I had some time to research and整理 (organize) it, and I record my learning here.
|
||||||
|
|
||||||
|
## Advantages
|
||||||
|
|
||||||
|
* Reduce size — font files are smaller than images
|
||||||
|
* Icon fidelity when scaling — solves 2x/3x and future n× image issues
|
||||||
|
* Easy to change color and size, image reuse
|
||||||
|
|
||||||
|
## Disadvantages
|
||||||
|
|
||||||
|
* Only suitable for
|
||||||
|
`single-color icons`
|
||||||
|
* Using Unicode characters is hard to understand
|
||||||
|
* Need to maintain the font library
|
||||||
|
|
||||||
|
There are many tutorials online about how to make IconFonts; I won't discuss that here.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
1. First pick some rich resource sites. I've used Alibaba's IconFont for years and didn't research others, so I'll use Alibaba's product here. Address: http://www.iconfont.cn/plus
|
||||||
|
|
||||||
|
2. Open the site and select suitable icons into the cart, as shown:
|
||||||
|

|
||||||
|
|
||||||
|
3. After selecting, view the cart and click to download the code.
|
||||||
|
|
||||||
|
4. Open the downloaded file; its structure is as follows. In iOS development we use the Unicode form of IconFont, so open demo_unicode.html
|
||||||
|

|
||||||
|
|
||||||
|
**Note:** Create UIFont using the font's PostScript name, not the file name; text values are 8-digit Unicode characters. We can open demo.html to find the HTML entity Unicode code for each icon. For example: the icon "店" corresponds to HTML entity Unicode code: 0x3439. Converted it becomes: \U00003439 — replace 0x with \U and pad with zeros to reach 8 characters.
|
||||||
|
|
||||||
|
# Using IconFont in Xcode
|
||||||
|
|
||||||
|
Initial attempt usage
|
||||||
|
|
||||||
|
1. First see how to use IconFont simply.
|
||||||
|
2. Add the downloaded **iconfont.ttf** into the Xcode project and ensure it's included in Build settings.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
3. How to use?
|
||||||
|
|
||||||
|
```objective-c
|
||||||
|
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:@"\U0000e696 \U0000e6ab \U0000e6ac \U0000e6ae"];
|
||||||
|
[attributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, 1)];
|
||||||
|
[attributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor orangeColor] range:NSMakeRange(3, 1)];
|
||||||
|
[attributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(9, 1)];
|
||||||
|
self.label.attributedText = attributedStr;
|
||||||
|
[self.view addSubview:self.label];
|
||||||
|
|
||||||
|
#pragma mark - getter and setter
|
||||||
|
-(UILabel *)label{
|
||||||
|
if (!_label) {
|
||||||
|
_label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, BoundWidth-200, 40)];
|
||||||
|
_label.font = [UIFont fontWithName:@"iconfont" size:24];
|
||||||
|
_label.textColor = [UIColor purpleColor];
|
||||||
|
}
|
||||||
|
return _label;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Further encapsulation for easier use
|
||||||
|
|
||||||
|
Generating a UIImage from IconFont only requires LBPIconFontmake(par1, par2, par3), where par1: the iconfont Unicode value; par2: image size; par3: image color. LBPIconFontmake is a macro: #define LBPIconFontmake(text,size,color) [[LBPFontInfo alloc] initWithText:text withSize:size andColor:color].
|
||||||
|
|
||||||
|
```objective-c
|
||||||
|
self.latestImageView.image = [UIImage iconWithInfo:LBPIconFontmake(@"\U0000e6ac", 60, @"000066") ];
|
||||||
|
```
|
||||||
|

|
||||||
|
|
||||||
|
1. LBPFontInfo encapsulates font information.
|
||||||
|
2. UIColor+picker sets color from a hex string.
|
||||||
|
3. LBPIconFont registers the IconFont into the system and uses it.
|
||||||
|
4. UIImage+LBPIconFont provides a UIImage category for using IconFont.
|
||||||
|
|
||||||
|
# Demo repository
|
||||||
|
|
||||||
|
https://github.com/FantasticLBP/IconFont_Demo
|
||||||
165
Chapter1 - iOS/1.2.md
Normal file
165
Chapter1 - iOS/1.2.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# Understanding Initializers
|
||||||
|
|
||||||
|
## Initializers
|
||||||
|
|
||||||
|
* The internal implementation of the new method is to call alloc first, then call init.
|
||||||
|
* alloc: Sends the alloc message to a class; alloc returns an instance of that class.
|
||||||
|
* init: An instance method whose role is to initialize the object.
|
||||||
|
* Steps to create an object: first use alloc to create an object, then use init to initialize it before using the object.
|
||||||
|
* Using an uninitialized object is dangerous.
|
||||||
|
* init method: Purpose — initialize the object and set initial values; this is called a constructor (initializer).
|
||||||
|
|
||||||
|
## Overriding init
|
||||||
|
|
||||||
|
* If you want the created object's properties to have values other than the default initialization values, you need to override init.
|
||||||
|
* Rules for overriding init:
|
||||||
|
* You must first call the superclass's init method (because initialization of the current class proceeds through [super init]), and assign the returned value to self.
|
||||||
|
* Calling init may fail; if it fails, return nil.
|
||||||
|
* Check whether the superclass initialized successfully. If self != nil, initialization succeeded.
|
||||||
|
* If initialization succeeded, initialize the current class's properties.
|
||||||
|
* Finally return self.
|
||||||
|
|
||||||
|
#### Clarifications:
|
||||||
|
|
||||||
|
1. Why call the superclass init method?
|
||||||
|
1. The current object has an isa pointer; the isa pointer is set through the superclass's init.
|
||||||
|
2. You need to ensure that the superclass's properties are also initialized.
|
||||||
|
2. Pattern for overriding init:
|
||||||
|
|
||||||
|
```
|
||||||
|
-(instancetype)init{
|
||||||
|
if (self = [super init]) {
|
||||||
|
// todo: custom property initialization
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```objc
|
||||||
|
// Person
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface Person : NSObject
|
||||||
|
@property NSString* name;
|
||||||
|
@property int age;
|
||||||
|
|
||||||
|
-(void)sayHi;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#import "Person.h"
|
||||||
|
@implementation Person
|
||||||
|
|
||||||
|
-(void)sayHi{
|
||||||
|
NSLog(@"Hi");
|
||||||
|
}
|
||||||
|
|
||||||
|
-(instancetype)init{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
self.name = @"杭城小刘";
|
||||||
|
self.age = 22;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
Person *p1 = [[Person alloc] init]; // p1.name = "杭城小刘", p1.age = 22;
|
||||||
|
Person *p2 = [Person new]; // p2.name = "杭城小刘", p2.age = 22;
|
||||||
|
```
|
||||||
|
|
||||||
|
If two classes have a composition relationship and one property is an object of another class, that property defaults to nil when the containing class is initialized. How to initialize it?
|
||||||
|
|
||||||
|
```
|
||||||
|
-(instancetype)init{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
self.name = @"lbp";
|
||||||
|
self.age = 22;
|
||||||
|
self.pig = [[Pig alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test
|
||||||
|
Person *p1 = [[Person alloc] init]; // p1.pig != nil
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom initializers
|
||||||
|
|
||||||
|
* Current situation: Although each created object's properties are not the default values, every initialized object has the same values.
|
||||||
|
* Requirement: Allow callers to decide the property values when instantiating.
|
||||||
|
* Solution: Custom initializer.
|
||||||
|
* Rules for custom initializers:
|
||||||
|
* The return type should be instancetype.
|
||||||
|
* The method name must begin with initWith.
|
||||||
|
* The implementation is similar to init.
|
||||||
|
* Note: You cannot use new to call a custom initializer. (new performs alloc then init; default init assigns the default property values.)
|
||||||
|
|
||||||
|
```
|
||||||
|
-(instancetype)initWithName:(NSString *)name andAge:(int)age{
|
||||||
|
if (self = [super init]) {
|
||||||
|
self.name = name;
|
||||||
|
self.age = age;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```objc
|
||||||
|
// Person
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
@interface Person : NSObject
|
||||||
|
@property NSString* name;
|
||||||
|
@property int age;
|
||||||
|
|
||||||
|
-(instancetype)initWithName:(NSString *)name andAge:(int)age;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#import "Person.h"
|
||||||
|
@implementation Person
|
||||||
|
|
||||||
|
-(instancetype)init{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
self.name = @"lbp";
|
||||||
|
self.age = 22;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// You cannot assign to self outside of an initializer.
|
||||||
|
// The compiler treats only methods starting with initWith as initializers.
|
||||||
|
|
||||||
|
-(instancetype)initWithName:(NSString *)name andAge:(int)age{
|
||||||
|
if (self = [super init]) {
|
||||||
|
self.name = name;
|
||||||
|
self.age = age;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
// Test
|
||||||
|
Person *p1 = [[Person alloc] init];
|
||||||
|
Person *p2 = [Person new];
|
||||||
|
Person *p3 = [[Person alloc] initWithName:@"杭城小刘2号" andAge:23];
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
An experiment about "custom initializers must start with initWith"
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The error message is clear: you cannot assign to self outside of an initializer.
|
||||||
|
|
||||||
|
Because the compiler considers only methods starting with initWith as initializers.
|
||||||
81
Chapter1 - iOS/1.3.md
Normal file
81
Chapter1 - iOS/1.3.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# loadView
|
||||||
|
|
||||||
|
1. Purpose: load the controller's view
|
||||||
|
2. When it's called: it's called the first time the controller's view is used
|
||||||
|
3. Use case: implement this method when you want to provide a custom view for the controller
|
||||||
|
|
||||||
|
Accessing the controller's view is equivalent to calling the controller's view getter:
|
||||||
|
```objective-c
|
||||||
|
-(UIView *)view
|
||||||
|
{
|
||||||
|
if(_view == nil){
|
||||||
|
[self loadView];
|
||||||
|
[self viewDidLoad];
|
||||||
|
}
|
||||||
|
return _view;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Controller view loading flow
|
||||||
|

|
||||||
|
|
||||||
|
- The controller's `init` method internally calls `initWithNibName`
|
||||||
|
|
||||||
|
`MyViewController *vc = [[MyViewController alloc] init];`
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
The system's decision logic assumes: no nibName specified; no custom loadView method; the controller is named ...Controller
|
||||||
|
|
||||||
|
Decision rules:
|
||||||
|
|
||||||
|
- Check whether a nibName was specified; if specified, load that nib
|
||||||
|
- Check whether there's an xib with the same name as the controller but without "Controller" in its name; if present, load it
|
||||||
|
- If the previous step doesn't find one, check whether an xib with the same name as the controller class exists; if present, load it
|
||||||
|
- If no xib describes the controller's view, do not load any xib
|
||||||
|
|
||||||
|
## How MyViewController loads its view
|
||||||
|
|
||||||
|
- Check whether an xibName was specified; if so, load the specified xib
|
||||||
|
- Check whether there's an xib with the same name as the controller class but without "Controller" in the name
|
||||||
|
- Check whether there's an xib with the same name as the controller class; if present, load it
|
||||||
|
- Otherwise, create an empty view directly
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
```objective-c
|
||||||
|
// in AppDelegate
|
||||||
|
ViewController *vc = [[ViewController alloc] init];
|
||||||
|
vc.view.backgroundColkor = [UIColor redColor];
|
||||||
|
self.window.rootViewController = vc;
|
||||||
|
[pself.window makeKeyAndVisable];
|
||||||
|
|
||||||
|
// ViewController
|
||||||
|
-(UIView *)view{
|
||||||
|
if(!_view){
|
||||||
|
[self loadView];
|
||||||
|
[self viewDidLoad];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)loadView{
|
||||||
|
UIView*view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||||
|
view.backgroundColor = [UIColor greenColor];
|
||||||
|
self.view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)viewDidload{
|
||||||
|
[super viewDidload];
|
||||||
|
self.view.backgroundColor = [UIColor brownColor];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### What color will the interface be at this point?
|
||||||
|
|
||||||
|
Many people might answer "green." Actually, the answer is red.
|
||||||
|
|
||||||
|
Why? In AppDelegate, `vc.view.backgroundColor` calls vc's view getter. Inside the getter it checks if `_view` exists; if not, it creates a new UIView by calling `[self loadView]`. After creating the view it calls `viewDidLoad`; if the view already exists it returns it directly. So the sequence is: first green, then brown, and finally red.
|
||||||
|
|
||||||
|
#### An official explanation
|
||||||
|
|
||||||
|

|
||||||
@@ -119,7 +119,7 @@ Part One mainly introduces problems encountered or interesting knowledge in iOS
|
|||||||
* [114. Swift optimizations](1.114.md)
|
* [114. Swift optimizations](1.114.md)
|
||||||
* [115. AI empowerment on the endpoint](1.115.md)
|
* [115. AI empowerment on the endpoint](1.115.md)
|
||||||
* [116. Deep dive into Swift classes](1.116.md)
|
* [116. Deep dive into Swift classes](1.116.md)
|
||||||
* [117. Swift protocol exploration](1.117.md]
|
* [117. Swift protocol exploration](1.117.md)
|
||||||
* [118. Swift error handling](1.118.md)
|
* [118. Swift error handling](1.118.md)
|
||||||
* [119. Analyze Swift String](1.119.md)
|
* [119. Analyze Swift String](1.119.md)
|
||||||
* [120. Swift access control](1.120.md)
|
* [120. Swift access control](1.120.md)
|
||||||
@@ -127,7 +127,16 @@ Part One mainly introduces problems encountered or interesting knowledge in iOS
|
|||||||
* [122. Swift literal fundamentals](1.122.md)
|
* [122. Swift literal fundamentals](1.122.md)
|
||||||
* [123. Swift pattern matching](1.123.md)
|
* [123. Swift pattern matching](1.123.md)
|
||||||
* [128. SwiftUI research](1.128.md)
|
* [128. SwiftUI research](1.128.md)
|
||||||
|
* [129. Swift Dictionary](1.129.md)
|
||||||
|
* [130. GCD](1.130.md)
|
||||||
|
* [131. Package management tools](1.131.md)
|
||||||
|
* [132. Dynamic debugging](1.132.md)
|
||||||
|
* [133. Using PGO in the compiler to optimize app performance](1.133.md)
|
||||||
|
* [134. Removing dead code](1.134.md)
|
||||||
|
* [135. Framework design](1.135.md)
|
||||||
|
* [136. Engineering practices](1.136.md)
|
||||||
|
* [137. Quality testing](1.137.md)
|
||||||
|
* [138. AFNetworking source code walkthrough](1.138.md)
|
||||||
* [139. Graphics rendering techniques](1.139.md)
|
* [139. Graphics rendering techniques](1.139.md)
|
||||||
* [140. Aspects](1.140.md)
|
* [140. Aspects](1.140.md)
|
||||||
* [143. AI empowerment on the endpoint](1.143.md)
|
* [143. AI empowerment on the endpoint](1.143.md)
|
||||||
|
|||||||
Reference in New Issue
Block a user