diff --git a/Chapter1 - iOS/1.1.md b/Chapter1 - iOS/1.1.md new file mode 100644 index 0000000..5977a00 --- /dev/null +++ b/Chapter1 - iOS/1.1.md @@ -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: +![](../assets/2017-05-28-iconfontPickUp.png) + +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 +![Downloaded file structure](../assets/2017-05-28-iconfontWorkDirectory.png) + +**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. + +![Xcode inclusion check](../assets/2017-05-28-iconfintWorkSetting.png) + +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") ]; +``` +![Encapsulated project structure](../assets//2017-05-28-iconfont.png) + +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 \ No newline at end of file diff --git a/Chapter1 - iOS/1.2.md b/Chapter1 - iOS/1.2.md new file mode 100644 index 0000000..0e8aaa0 --- /dev/null +++ b/Chapter1 - iOS/1.2.md @@ -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 + +@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 +@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]; +``` + +![init](../assets/2017-05-23-5-56-53.png) +![init](../assets/2017-05-23-5-57-08.png) + + +An experiment about "custom initializers must start with initWith" + +![initwith](../assets/2017-05-23-6-01-29.png) + +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. \ No newline at end of file diff --git a/Chapter1 - iOS/1.3.md b/Chapter1 - iOS/1.3.md new file mode 100644 index 0000000..7d68e8c --- /dev/null +++ b/Chapter1 - iOS/1.3.md @@ -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 +![Controller view loading flow](../assets/2287777-b6128646373dfffb.png) + +- 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 + +![Apple documentation](../assets/2287777-8ff7c3b976ffb29a.png) \ No newline at end of file diff --git a/Chapter1 - iOS/chapter1.md b/Chapter1 - iOS/chapter1.md index b5be711..a7e37fe 100644 --- a/Chapter1 - iOS/chapter1.md +++ b/Chapter1 - iOS/chapter1.md @@ -119,7 +119,7 @@ Part One mainly introduces problems encountered or interesting knowledge in iOS * [114. Swift optimizations](1.114.md) * [115. AI empowerment on the endpoint](1.115.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) * [119. Analyze Swift String](1.119.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) * [123. Swift pattern matching](1.123.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) * [140. Aspects](1.140.md) * [143. AI empowerment on the endpoint](1.143.md)