分类: IOS技术

IOS技术

iOS架构师_观察者模式

定义:
观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式),一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

%title插图%num

%title插图%num

示例代码:自己实现观察者模式

创建Protocol类型的接口文件SubProtocol协议类

SubProtocol.h

1 #import <Foundation/Foundation.h>
2
3 @protocol SubProtocol <NSObject>
4
5 //用户的信息和从某一个刊物接收的信息
6 – (void)subMessage:(id)message withSubNumber:(NSString *)withSubNumber;
7 @end

创建观察中心SubCenter类
SubCenter.h

1 #import <Foundation/Foundation.h>
2 #import “SubProtocol.h”
3
4 @interface SubCenter : NSObject
5 // 创建书刊订阅号
6 + (void)creatNumber:(NSString *)subNumber;
7
8 // 移除订阅号
9 + (void)removeNumber:(NSString *)subNumber;
10
11 // 添加用户
12 + (void)addUser:(id <SubProtocol>)user wihtNumber:(NSString *)userNumber;
13
14 // 移除用户
15 + (void)removeUser:(id <SubProtocol>)user withNumber:(NSString *)userNumber;
16
17 // 发送消息
18 + (void)sendMessage:(id)message withSubNumber:(NSString *)SubNumber;
19
20 @end

SubCenter.m

1 //
2 //  SubCenter.m
3 //  观察者模式
4 //
5 //  Created by James on 2017/12/9.
6 //  Copyright © 2017年 TZ. All rights reserved.
7
8
9 #import “SubCenter.h”
10
11
12 static NSMutableDictionary *bookCenter = nil;
13 @implementation SubCenter
14
15 //单例
16 + (void)initialize {
17     if (self == [SubCenter class]) {
18         bookCenter = [NSMutableDictionary dictionary];
19     }
20 }
21
22 // 创建书刊订阅号
23 + (void)creatNumber:(NSString *)subNumber {
24     //  NSHashTable 就是一个集合,但是它是弱引用的.
25     NSHashTable *hashTable = [self existNumber:subNumber];
26     if (hashTable == nil) {
27         hashTable = [NSHashTable weakObjectsHashTable];
28         [bookCenter setObject:hashTable forKey:subNumber];
29     }
30 }
31
32 // 移除订阅号
33 + (void)removeNumber:(NSString *)subNumber {
34     NSHashTable *hashTable = [self existNumber:subNumber];
35     if (hashTable) {
36         [bookCenter removeObjectForKey:subNumber];
37     }
38 }
39
40 // 添加用户
41 + (void)addUser:(id <SubProtocol>)user wihtNumber:(NSString *)userNumber {
42     NSHashTable *hashTable = [self existNumber:userNumber];
43     [hashTable addObject:user];
44 }
45
46 // 移除用户
47 + (void)removeUser:(id <SubProtocol>)user withNumber:(NSString *)userNumber {
48     NSHashTable *hashTable = [self existNumber:userNumber];
49     [hashTable removeObject:user];
50 }
51
52 // 发送消息
53 + (void)sendMessage:(id)message withSubNumber:(NSString *)SubNumber {
54     NSHashTable *hashTable = [self existNumber:SubNumber];
55     if (hashTable) {
56         //构造器
57         NSEnumerator *enumerato = [hashTable objectEnumerator];
58         id <SubProtocol> object = nil;
59
60         while (object = [enumerato nextObject]) {
61             if ([object respondsToSelector:@selector(subMessage:withSubNumber:)]) {
62                 [object subMessage:message withSubNumber:SubNumber];
63             }
64         }
65
66     }
67 }
68
69 #pragma mark – 私有方法
70 // 实现了代理方法
71 + (NSHashTable *)existNumber:(NSString *)subStringNumber {
72     return [bookCenter objectForKey:subStringNumber];
73 }
74
75 @end

ViewController调用

1 #import “ViewController.h”
2 #import “SubCenter.h”
3
4
5 static NSString *SCIENCE = @”SCIENCE”;
6 @interface ViewController () <SubProtocol>
7
8 @end
9
10 @implementation ViewController
11
12 – (void)viewDidLoad {
13     [super viewDidLoad];
14     // Do any additional setup after loading the view, typically from a nib.
15     // 创建订阅
16     [SubCenter creatNumber:SCIENCE];
17
18     // 添加订阅
19     [SubCenter addUser:self wihtNumber:SCIENCE];
20
21     // 发送消息
22     [SubCenter sendMessage:@”11″ withSubNumber:SCIENCE];
23 }
24
25 – (void)subMessage:(id)message withSubNumber:(NSString *)withSubNumber {
26     NSLog(@”—-%@—-%@”,message, withSubNumber);
27 }
28
29
30 @end

iOS架构师_策略模式

什么是策略设计模式?
概念:定义一系列的算法,并且将每个算法封装起来,算法之间还可以互相替换。这种设计模式称为策略模式。

为了解决if-else和switch-case的问题,在实际开发中,较长的if-else会使代码阅读困难。

%title插图%num

代码示例:下面是一个简单的if-else代码

Demo1

1 #import “ViewController.h”
2 typedef NS_ENUM(NSInteger) {
3     Count01,
4     Count02,
5     Count03,
6     Count04,
7     Count05,
8 }EnumCount;
9
10 @interface ViewController ()
11
12 @end
13
14 @implementation ViewController
15
16 – (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
17     EnumCount count = Count04;//声明枚举,并给了一个固定的输入值
18     if (count == 1) {
19         NSLog(@”count = %lu”,count);
20
21     } else if (count == 2) {
22         NSLog(@”count = %lu”,count);
23
24     }else if (count == 3) {
25         NSLog(@”count = %lu”,count);
26
27     }else if (count == 4) {
28         NSLog(@”count = %lu”,count);
29
30     } else {
31         NSLog(@”count = %lu”,count);
32     }
33 }
34 @end

我们使用正常的代码抽离方式对其优化分离。

创建一个NSObject的类,Logic

Logic.h

1 #import <Foundation/Foundation.h>
2
3 typedef NS_ENUM(NSInteger) {
4     Count01,
5     Count02,
6     Count03,
7     Count04,
8     Count05,
9 }EnumCount;
10
11 @interface Logic : NSObject
12
13 + (NSUInteger)logic:(NSUInteger)integer;
14
15 @end

Logic.m

1 #import “Logic.h”
2
3 @implementation Logic
4 + (NSUInteger)logic:(NSUInteger)integer {
5     NSUInteger num;
6     if (integer == 1) {
7         num = 1;
8
9     } else if (integer == 2) {
10         num = 2;
11
12     }else if (integer == 3) {
13         num = 3;
14
15     }else if (integer == 4) {
16         num = 4;
17
18     } else {
19         num = 0;
20     }
21     return num;
22 }
23 @end

那么修改ViewController如下

1 #import “ViewController.h”
2 #import “Logic.h”
3
4 @interface ViewController ()
5
6 @end
7
8 @implementation ViewController
9
10 – (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
11     EnumCount count = Count04;
12     NSUInteger integer = [Logic logic:count];
13     NSLog(@”integer = %lu”, integer);
14 }
15 @end

那么如何使用策略模式呢?

新建继承自NSObject 的 BaseType类

BaseType.h文件

1 #import <Foundation/Foundation.h>
2
3 typedef NS_ENUM(NSInteger) {
4     Count01,
5     Count02,
6     Count03,
7     Count04,
8     Count05,
9 }EnumCount;
10
11 @interface BaseType : NSObject
12 //返回计数结果
13 +(NSUInteger)backCountResult;
14 @end

BaseType.m

1 #import “BaseType.h”
2
3 @implementation BaseType
4 //抽象方法
5 +(NSUInteger)backCountResult {
6     //编写代码
7     return nil;
8 }
9 @end

创建继承自BaseType的子类CountTypes01

CountTypes01.h

1 #import “BaseType.h”
2
3 @interface CountTypes01 : BaseType
4
5 @end

CountTypes01.m

1 #import “CountTypes01.h”
2
3 @implementation CountTypes01
4
5 + (NSUInteger)backCountResult {
6     // 编写代码
7     return 10;
8 }
9 @end

那么修改ViewController如下

1 #import “ViewController.h”
2 #import “CountTypes01.h”
3
4 @interface ViewController ()
5
6 @end
7
8 @implementation ViewController
9
10 – (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
11     NSUInteger integer = [CountTypes01 backCountResult];
12
13     NSLog(@”integer = %lu”, integer);
14
15 }
16 @end

优缺点
策略模式的优点是能解决代码的耦合度,但是它是有牺牲的,为了解决代码耦合度,我们需要创建更多的类。

%title插图%num

Demo2
需求:验证两个textField的输入条件

%title插图%num

初始代码:
ViewController.m

1 #import “ViewController.h”
2
3 @interface ViewController () <UITextFieldDelegate>
4 @property (weak, nonatomic) IBOutlet UITextField *letterInput; /**< 字母输入 */
5 @property (weak, nonatomic) IBOutlet UITextField *numberInput; /**< 数字输入 */
6 @end
7
8 @implementation ViewController
9
10 – (void)viewDidLoad {
11     [super viewDidLoad];
12     // Do any additional setup after loading the view, typically from a nib.
13     self.letterInput.delegate = self;
14     self.numberInput.delegate = self;
15 }
16
17 – (IBAction)btnClick:(id)sender {
18     [self.view endEditing:YES];
19 }
20
21 #pragma mark – UITextFieldDelegate
22 – (void)textFieldDidEndEditing:(UITextField *)textField {
23     if (textField == self.letterInput) {
24         // 验证它的输入值, 确保它输入的是字母
25         NSString *outputLatter = [self validateLatterInput:textField];
26         if (outputLatter) {
27             NSLog(@”—%@”,outputLatter);
28         }else {
29             NSLog(@”—输入是空的”);
30         }
31
32     } else if (textField == self.numberInput) {
33        // 验证它的输入值, 确保它输入的是数字
34         NSString *outputNumber = [self validateNumberInput:textField];
35         if (outputNumber) {
36             NSLog(@”—%@”,outputNumber);
37         }else {
38             NSLog(@”—输入是空的”);
39         }
40     }
41 }
42
43 #pragma mark – 验证输入
44 – (NSString *)validateLatterInput:(UITextField *)textField {
45     if (textField.text.length == 0) {
46         return nil;
47     }
48
49     // ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
50     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@”^[a-zA-Z]*$” options:NSRegularExpressionAnchorsMatchLines error:nil];
51     //NSMatchingAnchored 从开始处就进行*限匹配
52     NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
53
54     NSString *outLatter = nil;
55     // 进行判断,匹配不符合表示0的话, 就走下面的逻辑
56     if (numberOfMatches == 0) {
57         outLatter = @”不全是字母, 输入有误,请重新输入”;
58     } else {
59         outLatter = @”输入正确,全部是字母”;
60     }
61
62     return outLatter;
63 }
64
65 – (NSString *)validateNumberInput:(UITextField *)textField {
66     if (textField.text.length == 0) {
67         return nil;
68     }
69
70     // ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
71     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@”^[0-9]*$” options:NSRegularExpressionAnchorsMatchLines error:nil];
72
73     NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
74
75     NSString *outLatter = nil;
76     // 进行判断,匹配不符合表示0的话, 就走下面的逻辑
77     if (numberOfMatches == 0) {
78         outLatter = @”不全是数字, 输入有误,请重新输入”;
79     } else {
80         outLatter = @”输入正确,全部是数字”;
81     }
82
83     return outLatter;
84
85 }
86
87
88 @end

我们知道,所有的设计模式都是为了代码解耦合所使用的,代价肯定是需要创建其他的类,将代码分离。

那么我们如何使用策略模式来优化代码呢?

首先我们创建一个继承自NSObject的抽象类:InputTextFieldValidate

InputTextFieldValidate.h

1 #import “InputTextFieldValidate.h”
2
3 @implementation InputTextFieldValidate
4 – (BOOL)validateInputTextField:(UITextField *)textField {
5     return NO;
6 }
7 @end

InputTextFieldValidate.m

1 #import “LatterTextFieldValidate.h”
2
3 @implementation LatterTextFieldValidate
4
5 – (BOOL)validateInputTextField:(UITextField *)textField {
6     if (textField.text.length == 0) {
7         self.attributeInputStr = @”字母不能是空的”;
8         return nil;
9     }
10
11     // ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
12     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@”^[a-zA-Z]*$” options:NSRegularExpressionAnchorsMatchLines error:nil];
13
14     NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
15
16 //    NSString *outLatter = nil;
17     // 进行判断,匹配不符合表示0的话, 就走下面的逻辑
18     if (numberOfMatches == 0) {
19         self.attributeInputStr = @”不全是字母, 输入有误,请重新输入”;
20     } else {
21         self.attributeInputStr = @”输入正取,全部是字母”;
22     }
23
24     return self.attributeInputStr == nil ? YES : NO;
25 }
26 @end

 

然后创建一个继承自UITextField的类:CustomTextField(自定义的TextField)

CustomTextField.h

1 #import <UIKit/UIKit.h>
2 #import “InputTextFieldValidate.h”
3
4 @interface CustomTextField : UITextField
5
6 // 抽象的策略
7 @property (nonatomic, strong) InputTextFieldValidate *inputValidate;
8
9 // 验证是否符合要求
10 – (BOOL)validate;
11 @end

CustomTextField.m

1 #import <UIKit/UIKit.h>
2 #import “InputTextFieldValidate.h”
3
4 @interface CustomTextField : UITextField
5
6 // 抽象的策略
7 @property (nonatomic, strong) InputTextFieldValidate *inputValidate;
8
9 // 验证是否符合要求
10 – (BOOL)validate;
11 @end

ViewController.m就简洁多了,修改如下:

1 #import <UIKit/UIKit.h>
2 #import “InputTextFieldValidate.h”
3
4 @interface CustomTextField : UITextField
5
6 // 抽象的策略
7 @property (nonatomic, strong) InputTextFieldValidate *inputValidate;
8
9 // 验证是否符合要求
10 – (BOOL)validate;
11 @end

ViewController.m就简洁多了,修改如下:

1 #import “ViewController.h”
2 #import “CustomTextField.h”
3 #import “LatterTextFieldValidate.h”
4 #import “NumberTextFieldValidate.h”
5
6
7 @interface ViewController () <UITextFieldDelegate>
8 @property (weak, nonatomic) IBOutlet CustomTextField *letterInput; /**< 字母输入 */
9 @property (weak, nonatomic) IBOutlet CustomTextField *numberInput; /**< 数字输入 */
10 @end
11
12 @implementation ViewController
13
14 – (void)viewDidLoad {
15     [super viewDidLoad];
16     // Do any additional setup after loading the view, typically from a nib.
17     self.letterInput.delegate = self;
18     self.numberInput.delegate = self;
19
20     // 初始化
21     self.letterInput.inputValidate = [LatterTextFieldValidate new];
22     self.numberInput.inputValidate = [NumberTextFieldValidate new];
23
24 }
25
26 – (IBAction)btnClick:(id)sender {
27     [self.view endEditing:YES];
28 }
29
30 #pragma mark – UITextFieldDelegate
31 – (void)textFieldDidEndEditing:(UITextField *)textField {
32     if ([textField isKindOfClass:[CustomTextField class]]) {
33         [(CustomTextField *)textField validate];
34     }
35 }
36
37 @end

优点:控制器代码简洁,分离代码复用性高,逻辑清晰,方便拓展。

用Mac自带的airport抓包以及用aircrack-ng进行Wi-Fi密码破解

用Mac自带的airport抓包以及用aircrack-ng进行Wi-Fi密码破解

电脑配置
MacAir 2015年款
版本:10.15.2
内存:8g
Mac上需要Xcode,提前安装Xcode会为我们解决很多不必要的麻烦,如果提示版本低无法安装,直接在App store中搜索macOS Mojave(这个版本是14)下载安装即可。

声明:本文章只供学习使用,请勿用做非法用途
本人菜鸟,看了很多文章,为大家总结一下,欢迎指教,只为和大家学习交流。

了解一下Mac自带的Wi-Fi工具airport
在终端中输入
sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s
1

%title插图%num

此命令主要为了获取ssid bssid ch等信息。

如果你不想每次启用airport时输入一长串的命令 就定义一个alisa吧.
vim ~/.bash_profile
1
将下面这段话插入进去

alias airport=”/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s”
1

%title插图%num
保存并退出vim,如果你不了解vim的使用,可以借阅以下链接
vi/vim的使用方法
为了让我们的alias快速生效,我们还需要手动更新一下,在终端中输入以下代码即可生效
source ~/.bashrc
1
再之后 你不需要输入一长串的命令,直接输入airport就可以得到周围Wi-Fi的信息为下一步的抓包准备了。

为你的Mac安装aircrack-ng
在这之前我搜索了很多文章都推荐用Macports来安装aircrack-ng但是我尝试多次始终报错,就采取了homebrew来安装aircrack-ng如果你和我一样报错,那就用brew来安装吧
Homebrew的安装下载以下文件到你的Mac电脑中,
连接:链接:https://pan.baidu.com/s/1eRqswzRXeARginnEPtsK8Q
提取码:rxit

在终端中运行以下命令
ruby /Users/你自己的用户名/Downloads/brew_install.rb
1
我已经安装过了就不再安装了,接下来你可能需要等待10分钟左右,判断你的Homebrew是否安装完成输入brew -v即可,输入后他将显示版本号等信息,说明你安装成功了。

安装aircrack-ng
上面已经安装好了Homebrew直接运行以下命令即可安装aircrack-ng,接下来就让我们的brew来为我们安装aircrack-ng吧
brew install aircrack-ng
1
接下来开始等待brew来为我们安装吧。

好了,一切准备就绪,开工!

终端中输入airport(前面已经定义了alias了)
airport
1

%title插图%num

看ssid列找到你想要的破解的Wi-Fi名称,并记录ch信道下的数字。

开始用你的网卡进行监听并获取握手包,假如我们想要监听Wi-Fi他的信道是40,就输入以下命令 (en0是你的网卡名称,可通过ifconfig获取这里不再叙述了,一般都是en0)
airport en0 sniff 40
1
此时我们需要等待抓包,当然他可能会提示你
Could not open device en0 (en0: You don’t have permission to capture on that device ((cannot open BPF device) /dev/bpf0: Permission denied)).
处理方法:

cd /dev
ls -la | grep bp

whoami //查看当前的用户名
sudo chown 上面看到的用户名:admin bp*

权限问题都可用此方法处理,至此,处理了网卡权限不足问题,回归到前面,继续输入抓包命令
airport en0 sniff 40

开始监听的时候你的Wi-Fi图标会变成一个眼睛以及终端的提醒
Capturing 802.11 frames on en0.

%title插图%num

通常我们监听的时间会持续5到十分钟,结束监听的命令
control+c
结束后,会提醒我们**.cap**文件保存的位置,

%title插图%num
6、打开访达(finder)按shift+command+g出现搜索框,键入/tmp到达文件存放的位置

%title插图%num

 

进入后我们会看到刚才的那个.cap文件

%title插图%num

好了 我们已经找到这个文件了,输入下面的代码,看是否含有密码信息
sudo aircrack-ng /tmp/airportSniffTRT4xj.cap
1
WPA (0 handshake)里面的0代表失败,1代表成功,我们要找到带有1的哪一行,可以直接搜索command+f

%title插图%num

我们可以找到第1562行抓取成功,好了接下来就让我们开始尝试米密码破解吧

尝试Wi-Fi密码破解
先进入我们密码文本存放的位置,假如在你的桌面上有个存放密码的文件夹WiFi,那就输入以下命令
cd ~/Desktop/wifi
1
再使用aircrack-ng进行破解,输入以下命令
sudo aircrack-ng -w 123.txt /tmp/*.cap
1

在这里输入刚才有**WPA (1 handshake)**这一行,我的是1562行,开始尝试破解。

%title插图%num

可以看到很快就破解了这个弱密码1234567890,当然这是在运气很好的情况下,如果你的字典很弱,你需要收集很多字典来为你的渗透做准备

react native ios打包到真机

每当在模拟器上完成了开发,都想到真机上秀秀,正好前段时候买了一个mac,哈哈有机会了。

%title插图%num

前篇文章以android为例,这里就以ios为例,讲一下打包到iphone真机的流程。

 

一、前置

1.首先你得有一部iphone

2.首先react native的环境要正确安装,还未完成这一步的,请到官网或中文站查看具体流程

3.xcode等环境安装完毕

4.rn应用能在模拟器中跑起来,至少不要有致命错误吧

 

二、生成jsbundle

1.进入rn项目的ios工程文件夹,找到和rn项目同名的文件件,打开AppDelegate.m文件,将这一行注释掉(为了方便真机和模拟器间的切换,尽量注释):

jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@”index.ios” fallbackResource:nil];
新加一行:

jsCodeLocation = [[NSBundle mainBundle] URLForResource:@”index.ios” withExtension:@”jsbundle”];
如果需要切换回模拟器调试,只需要将新加这行注释掉,并恢复原代码即可。

新加这行代码大概意思就是告诉native rn代码的入口,我们会在下一步生成这个jsbundle。

 

2.打开终端,进入你的rn工程,在根目录下执行bundle命令:

react-native bundle –entry-file ./index.ios.js –bundle-output ./ios/bundle/index.ios.jsbundle –platform ios –assets-dest ./ios/bundle –dev false
参数说明:

–entry-file 指定入口文件 因为要打包ios平台,所以指定为rn项目的index.ios.js作为入口

–bundle-output 指定输出的jsbundle文件路径和文件名 指定到rn项目的ios工程文件夹下,记得一定要先创建bundle文件夹,不然终端会报文件夹找不到的错误

–platform 指定平台类型

–assets-dest 指定资源文件夹路径 assets文件夹的路径,包含图片、node模块等资源

–dev 是否为开发模式 如果设置为false,不会产生警告,并且bundle会被压缩

还有其他命令,比如:transformer、prepack、bundle-encoding等,可以到官网查看具体介绍。

 

bundle生成完成后,终端会有类似提示:

%title插图%num

 

3.用xcode Open another project打开rn项目的ios工程文件夹:

%title插图%num

%title插图%num

 

将之前打包好的jsbundle和assets拖入rndemo这个文件夹下面,注意一定要选择 Create folder references:

%title插图%num

三、配置网络访问白名单

应用中如果有网络请求,这一步必不可少,要不然会出现网络请求失败的错误提示。

1.打开Info.plist:

%title插图%num

2.在App Transport Security Settings下添加key:Exception Domains,类型为Dictionary。

3.在Exception Domains下添加你的应用可能会访问到的域名,key为域名,类型为Dictionary。需要注意的是:

iOS 9及以上版本,非HTTS的网络是被禁止的,当然我们也可以把NSAllowsArbitraryLoads设置为YES禁用ATS。不过iOS 10从2017年1月1日起苹果不允许我们通过这个方法跳过ATS,也就是说强制我们用HTTPS,如果不这样的话提交App可能会被拒*。但是我们可以通过NSExceptionDomains来针对特定的域名开放HTTP可以容易通过审核。每个域名都需要三个属性,key分别为:

NSIncludesSubdomains 是否包含子域 设置为true

NSExceptionRequiresForwardSecrecy 指定域名是否支持Forward Secrecy 设置为false

NSExceptionAllowsInsecureHTTPLoads 是否能使用http协议,默认是只能请求https的 设置为true

类型都为Boolean。

比如这里,我增加了api.douban.com这个白名单域,因为它本身就是走的https协议,那三个子属性我便没再做配置。应用需要访问的域都可以加到这里。

 

四、设置应用图标和闪屏图片(启动图)

在xcode中点击Images.xcassets文件夹,这是保存应用图标和闪屏等的文件夹:

%title插图%num

可以看到应用图标是按照尺寸分类了的,具体每个类型的图片大小要求可以自行查找资料,一定要保证同样的分辨率,而且不需要是圆角,否则在编译的时候会有警告提示。

闪屏的话,可以右键添加LaunchImage,也是同样的按尺寸和方向分类的,只需要拖入对应的图片即可。

图标和启动图我都是胡乱弄的,要弄齐所有还是很麻烦。

 

五、连接iphone到电脑,并让它们处于wifi的同一网段

1.连接好iphone以后,将设备选择为你的iphone,并点击xcode左上方的build按钮,就可以执行构建了:

%title插图%num

2.构建完成以后,xcode会有个没法启动应用的提示。原因是你的手机没有信任这个程序,在手机设置中:通用->设备管理->开发者应用 中信任这个应用,然后点击应用图标即可启动应用了。

 

构建中途可能会有错误或者警告提示,可根据具体的提示查找解决办法。

我遇到过两个错误:

1.app id不唯一,在这里可以重新设置:

%title插图%num

2.签名那里没有指定一个team:

%title插图%num

在这里可以按照提示一步一步设置

 

还需要注意的是部署的目标要和iphone系统版本一致:

%title插图%num

对于native小白来说,这些的确很陌生,哈哈

*后,祝你玩的愉快

RN集成到IOS的坑

4个文件,然后将其中的”localhost”改为你的电脑的IP地址

192.168.3.15

RCTWebSocketExecutor.m
RCTPackagerConnectionBridgeConfig.m
RCTInspectorDevServerHelper.mm
RCTBundleURLProvider.m
if (!host) {
//host = @”localhost”;
host = @”192.168.3.15″;

scheme = @”http”;
}

 

iOS原生混合RN开发*佳实践

做过原生iOS开发或者Android开发的同学们肯定也都了解Hybrid,有一些Hybrid的开发经验,目前我们企业开发中运用*广泛的Hybrid App技术就是原生与H5 hybrid,在早期的时候,可能部分同学也接触过PhoneGap等hybrid技术,今天我们就简单来聊下一种比较新的Hybrid技术方案,原生App与ReactNativie Hybrid。

示例Demo地址

  • 初级Demo示例
  • 高级Demo示例

具体步骤

  • 创建一个iOS原生项目
  • 将iOS原生项目支持pod
  • 调整目前项目工程的文件夹结构
  • 添加RN依赖相关文件
  • 安装React Native
  • 修改Podfile文件,原生安装React Native依赖库
  • 在iOS原生页面填加RN页面入口
  • 修改RN入口文件 index.ios.js
  • 执行npm start 运行项目

创建一个iOS原生项目

使用Xcode创建一个空的项目,这个应该不用多说了

项目支持pod

这一操作步骤同样也很简单,我们只需要执行下面的几条命令即可,如果对cocoapods 安装使用不熟悉的同学请参照作者简书

  • 创建podfile文件,我们在有xcodeproj文件的同级目录下执行下面命令,这时我们的项目文件中就多了一个Podfile文件
  1. $ pod init
  2. 复制代码
  • 执行pod install 命令来安装pod,同样,这个命令也是在有xcodeproj同级目录下,安装完成后,我们的项目多了一个
  1. $ pod install
  2. 复制代码

注意: 这里对原生iOS不熟悉的同学们需要注意了,当我们使用pod来作为库管理工具,后面我们打开项目运行,我们就需要打开上图所示的xcworkspace文件了

调整目前项目工程的文件夹结构

这里对文件夹做结构调整是为了后期更好的将Android原始项目也使用RN Hybrid,使iOS和Android共享一份React Native框架,共享同一份JS文件,调整的后的文件夹结构如下

添加RN依赖相关文件

到这里,我们原生的iOS项目目录结构已近调整完毕,后面我们需要处理的都是RN相关的内容了,这里需要创建的文件有点多,大家可以直接将示例Demo中的这几个文件直接拖到自己的项目中,然后在做修改即可

  • 首先我们需要创建package.json文件
  • 创建index.ios.js文件
  • 创建index.android.js文件
  • 创建bundle文件夹,注意这个文件夹是后面我们接入CodePush热更新时使用的

安装React Native

安装React Native这个也很简单,我们也是简单的执行下面的命令即可,注意:执行npm 系列的命令,我们都需要在项目根目录(有package.json文件的目录)下执行

  1. $ npm install
  2. 复制代码

package.json文件内容如下

  1. {
  2. “name”: “iOSHybridRNDemo”,
  3. “version”: “0.0.1”,
  4. “private”: true,
  5. “scripts”: {
  6. “start”: “node node_modules/react-native/local-cli/cli.js start”
  7. },
  8. “dependencies”: {
  9. “prop-types”: “^15.6.1”,
  10. “react”: “16.0.0”,
  11. “react-native”: “0.50.3”,
  12. “react-native-code-push”: “^5.2.2”,
  13. “react-native-root-toast”: “^1.3.0”,
  14. “react-native-router-flux”: “^4.0.0-beta.24”,
  15. “react-native-simple-store”: “^1.3.0”,
  16. “react-native-storage”: “^0.2.2”,
  17. “react-native-vector-icons”: “^4.3.0”,
  18. “react-redux”: “^5.0.6”,
  19. “redux”: “^3.7.2”,
  20. “redux-actions”: “^2.2.1”,
  21. “redux-promise-middleware”: “^4.4.1”,
  22. “redux-thunk”: “^2.2.0”
  23. },
  24. “devDependencies”: {
  25. “babel-jest”: “22.4.1”,
  26. “babel-preset-react-native”: “4.0.0”,
  27. “jest”: “22.4.2”,
  28. “react-test-renderer”: “16.0.0”
  29. },
  30. “jest”: {
  31. “preset”: “react-native”
  32. }
  33. }
  34. 复制代码

注意:因为我们项目中使用到了react-native-vector-icons 这个iconFont组件需要依赖原生,所以我们执行完 npm install 之后,我们还需要 再执行一个 react-native link react-native-vector-icons 命令来安装原生依赖

  1. $ react-native link react-native-vector-icons
  2. 复制代码

当我们执行完npm install 命令之后,我们再打开项目目录,发现多了一个 node_modules 文件夹,这个文件夹就是我们安装的React Native所有的依赖库

修改Podfile文件,原生安装React Native依赖库

后面我们都是使用Pod来管理原生的依赖库,安装React Native依赖库,我们只需要将下面的Podfile文件中的内容添加进去,执行 pod install 安装即可

Podfile文件

  1. # Uncomment the next line to define a global platform for your project
  2. platform :ios, ‘9.0’
  3. # Uncomment the next line if you’re using Swift or would like to use dynamic frameworks
  4. # use_frameworks!
  5. target ‘iOSHybridRNDemo’ do
  6. # Pods for iOSHybridRNDemo
  7. #***********************************************************************#
  8. # ‘node_modules’目录一般位于根目录中
  9. # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
  10. pod ‘React’, :path => ‘../node_modules/react-native’, :subspecs => [
  11. ‘Core’,
  12. ‘RCTText’,
  13. ‘RCTImage’,
  14. ‘RCTActionSheet’,
  15. ‘RCTGeolocation’,
  16. ‘RCTNetwork’,
  17. ‘RCTSettings’,
  18. ‘RCTVibration’,
  19. ‘BatchedBridge’,
  20. ‘RCTWebSocket’,
  21. ‘ART’,
  22. ‘RCTAnimation’,
  23. ‘RCTBlob’,
  24. ‘RCTCameraRoll’,
  25. ‘RCTPushNotification’,
  26. ‘RCTLinkingIOS’,
  27. ‘DevSupport’
  28. # 在这里继续添加你所需要的模块
  29. ]
  30. # 如果你的RN版本 >= 0.42.0,请加入下面这行
  31. pod “yoga”, :path => “../node_modules/react-native/ReactCommon/yoga”
  32. #***********************************************************************#
  33. pod ‘RNVectorIcons’, :path => ‘../node_modules/react-native-vector-icons’
  34. end
  35. 复制代码

注意: #*************************# 中间的内容是我们需要添加的RN依赖库,后面我们所有pod 相关的命令,我们都需要iOS根目录(有Podfile文件的目录)下执行

  • 执行安装命令
  1. $ pod install
  2. 复制代码

在iOS原生页面填加RN页面入口

现在我就来实现从原生页面跳RN页面

  • 使用RN提供一个View视图代码如下
  1. NSURL * jsCodeLocation;
  2. #ifdef DEBUG
  3. NSString * strUrl = @“http://localhost:8081/index.ios.bundle?platform=ios&dev=true”;
  4. jsCodeLocation = [NSURL URLWithString:strUrl];
  5. #else
  6. jsCodeLocation = [CodePush bundleURL];
  7. #endif
  8. NSDictionary *params = @{@“componentName”:@“MeApp1”, @“args”:@{@“params”:@“这是原生传递的参数”}};
  9. RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
  10. moduleName:@“iOSRN”
  11. initialProperties:params
  12. launchOptions:nil];
  13. self.view = rootView;
  14. 复制代码

修改RN入口文件 index.ios.js

修改RN页面的入口文件,这里当是iOS入口我们修改index.ios.js文件,当Android入口,我们修改index.android.js文件

  • index.ios.js文件
  1. import React, {Component} from ‘react’
  2. import {
  3. Platform,
  4. StyleSheet,
  5. Text,
  6. View,
  7. AppRegistry
  8. } from ‘react-native’;
  9. const instructions = Platform.select({
  10. ios: ‘Press Cmd+R to reload,\n’ +
  11. ‘Cmd+D or shake for dev menu’,
  12. android: ‘Double tap R on your keyboard to reload,\n’ +
  13. ‘Shake or press menu button for dev menu’,
  14. });
  15. type Props = {};
  16. export default class App extends Component<Props> {
  17. render() {
  18. return (
  19. <View style={styles.container}>
  20. <Text style={styles.welcome}>
  21. Welcome to React Native!
  22. </Text>
  23. <Text style={styles.instructions}>
  24. To get started, edit App.js
  25. </Text>
  26. <Text style={styles.instructions}>
  27. {instructions}
  28. </Text>
  29. </View>
  30. );
  31. }
  32. }
  33. const styles = StyleSheet.create({
  34. container: {
  35. flex: 1,
  36. justifyContent: ‘center’,
  37. alignItems: ‘center’,
  38. backgroundColor: ‘#F5FCFF’,
  39. },
  40. welcome: {
  41. fontSize: 20,
  42. textAlign: ‘center’,
  43. margin: 10,
  44. },
  45. instructions: {
  46. textAlign: ‘center’,
  47. color: ‘#333333’,
  48. marginBottom: 5,
  49. },
  50. });
  51. AppRegistry.registerComponent(‘iOSHybridRNDemo’, () => App)
  52. 复制代码

执行npm start 运行项目

到这里,我们一个简单的原生嵌入RN开发工程就搭建完成了,我们执行下面命令来运行项目,查看效果

  • 开启node 服务
  1. $ npm start
  2. 复制代码
  • 运行效果

(006)RN开发之iOS真机调试

*步,使用Xcode打开项目
第二步,使用真机运行项目
第三步,晃动手机,选择Debug JS Remotely
浏览器会自动打开地址:http://localhost:8081/debugger-ui/
第四步,将localhost修改为本机ip地址
查看电脑ip地址的方法:点击WiFi图标 –> 打开网络偏好设置…

将第三步中的地址改为:http://192.168.37.66:8081/debugger-ui/ (说明:192.168.37.66是我电脑的ip地址,这里需要替换为你自己的电脑的ip地址)

第五步,使用Xcode重新运行项目
8

第三章Mac系统下安装Vue-cli详细步骤

第三章Vue-cli安装

因为是mac系统,所以和视频里老师讲的有些许不同。
1.首先打开终端

%title插图%num

按照老师的操作,首先检查node版本
下面是我的操作
打开终端,输入命令 node -v 我去,找不到node。。。。。
好吧,去这个地方下载mac版本的node
下载地址:https://nodejs.org/en/download/ (选择mac os)
安装完毕,有了

%title插图%num
2.输入 sudo npm install -g vue-cli 这个命令

因为npm的关系所以有点进度有点慢,等待,终于好了

%title插图%num
3.输入 命令 vue 查看一下

%title插图%num
执行 vue list 查看

%title插图%num

这些是列出了可以用的模板

4.安装webpack模板,并设置工程信息
输入命令 vue init webpack sell
注释:sell是名称,自己可以随意命名

接下来输入项目名称,项目描述,作者,是否安装路由,是否使用后ES检测器,输入 y,需要,是否需要前端测试库n 不需要,完成。

%title插图%num
然后输入命令cd sell

输入命令sudo npm install

%title插图%num
输入命令sudo npm run dev

%title插图%num

以上!!mac系统安装Vue-cli完成!
etails/72902312

(0105)iOS开发之iOS13 暗黑模式(Dark Mode)适配

导读:
Material Design & iOS 13 黑暗模式总结探索

暗黑模式苹果开发文档

如何不进行系统切换样式的适配

注意

1  同一工程内多个Assets文件在打包后,就会生成一个Assets.car 文件,所以要保证Assets内资源文件的名字不能相同。
2  苹果官方强烈建议适配暗黑模式(Dark Mode)此功能也是为了开发者能慢慢将应用适配暗黑模式,所以想通过此功能不进行适配暗黑模式,预计将会被拒。

暗黑模式的优点:
省电
沉浸式效果明显
深色背景的优势是可以突出与我们主要交互操作的内容,弱化其他辅助元素并降低屏幕整体的亮度减少视觉压力。
全局关闭暗黑模式
在Info.plist 文件中,添加UIUserInterfaceStyle key 名字为 User Interface Style 值为String, 将UIUserInterfaceStyle key 的值设置为 Light

单个界面不遵循暗黑模式
UIViewController与UIView 都新增一个属性 overrideUserInterfaceStyle
将 overrideUserInterfaceStyle 设置为对应的模式,则强制限制该元素与其子元素以设置的模式进行展示,不跟随系统模式改变进行改变

设置 ViewController 的该属性, 将会影响视图控制器的视图和子视图控制器采用该样式
设置 View 的该属性, 将会影响视图及其所有子视图采用该样式
设置 Window 的该属性, 将会影响窗口中的所有内容都采用样式,包括根视图控制器和在该窗口中显示内容的所有演示控制器(UIPresentationController)
如何在代码里进行适配颜色(UIColor)

1 + (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
2 – (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);

e.g.

1 [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trait) {
2     if (trait.userInterfaceStyle == UIUserInterfaceStyleDark) {
3         return UIColorRGB(0x000000);
4     } else {
5         return UIColorRGB(0xFFFFFF);
6     }
7  }];

系统调用更新方法,自定义重绘视图
当用户更改外观时,系统会通知所有window与View需要更新样式,在此过程中iOS会触发以下方法

1 traitCollectionDidChange(_:)
2 layoutSubviews()
3 draw(_:)
4 updateConstraints()
5 tintColorDidChange()

UIViewController

1 traitCollectionDidChange(_:)
2 updateViewConstraints()
3 viewWillLayoutSubviews()
4 viewDidLayoutSubviews()

UIPresentationController

1 traitCollectionDidChange(_:)
2 containerViewWillLayoutSubviews()
3 containerViewDidLayoutSubviews()

适配Dark Mode
颜色适配
图片适配
1 颜色适配
iOS13系统动态颜色
iOS13 之前 UIColor只能表示一种颜色,而从 iOS13 开始UIColor是一个动态的颜色,在LightMode和Dark Mode可以分别设置不同的颜色。
iOS13系统提供了一些动态颜色

1 @property (class, nonatomic, readonly) UIColor *systemBrownColor        API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
2 @property (class, nonatomic, readonly) UIColor *systemIndigoColor       API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
3 @property (class, nonatomic, readonly) UIColor *systemGray2Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
4 @property (class, nonatomic, readonly) UIColor *systemGray3Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
5 @property (class, nonatomic, readonly) UIColor *systemGray4Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
6 @property (class, nonatomic, readonly) UIColor *systemGray5Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
7 @property (class, nonatomic, readonly) UIColor *systemGray6Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
8 @property (class, nonatomic, readonly) UIColor *labelColor              API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
9 @property (class, nonatomic, readonly) UIColor *secondaryLabelColor     API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
10 @property (class, nonatomic, readonly) UIColor *tertiaryLabelColor      API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
11 @property (class, nonatomic, readonly) UIColor *quaternaryLabelColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
12 @property (class, nonatomic, readonly) UIColor *linkColor               API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
13 @property (class, nonatomic, readonly) UIColor *placeholderTextColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
14 @property (class, nonatomic, readonly) UIColor *separatorColor          API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
15 @property (class, nonatomic, readonly) UIColor *opaqueSeparatorColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
16 @property (class, nonatomic, readonly) UIColor *systemBackgroundColor                   API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
17 @property (class, nonatomic, readonly) UIColor *secondarySystemBackgroundColor          API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
18 @property (class, nonatomic, readonly) UIColor *tertiarySystemBackgroundColor           API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
19 @property (class, nonatomic, readonly) UIColor *systemGroupedBackgroundColor            API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
20 @property (class, nonatomic, readonly) UIColor *secondarySystemGroupedBackgroundColor   API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
21 @property (class, nonatomic, readonly) UIColor *tertiarySystemGroupedBackgroundColor    API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
22 @property (class, nonatomic, readonly) UIColor *systemFillColor                         API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
23 @property (class, nonatomic, readonly) UIColor *secondarySystemFillColor                API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
24 @property (class, nonatomic, readonly) UIColor *tertiarySystemFillColor                 API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
25 @property (class, nonatomic, readonly) UIColor *quaternarySystemFillColor               API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);

① 实例

1 [self.view setBackgroundColor:[UIColor systemBackgroundColor]];
2 [self.titleLabel setTextColor:[UIColor labelColor]];
3 [self.detailLabel setTextColor:[UIColor placeholderTextColor]];

效果展示

%title插图%num

用法和iOS13之前的一样,使用系统提供的这些动态颜色,不需要其他的适配操作

自定义动态UIColor
在实际开发过程,系统提供的这些颜色还远远不够,因此我们需要创建更多的动态颜色
初始化动态UIColor方法

iOS13 UIColor增加了两个初始化方法,使用以下方法可以创建动态UIColor
注:一个是类方法,一个是实例方法

1 + (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
2 – (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);

这两个方法要求传一个block进去
当系统在LightMode和DarkMode之间相互切换时就会触发此回调
这个block会返回一个UITraitCollection类
我们需要使用其属性userInterfaceStyle,它是一个枚举类型,会告诉我们当前是LightMode还是DarkMode

1 typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) {
2     UIUserInterfaceStyleUnspecified,
3     UIUserInterfaceStyleLight,
4     UIUserInterfaceStyleDark,
5 } API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos);

② 实例

1 UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
2         if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
3             return [UIColor redColor];
4         }
5         else {
6             return [UIColor greenColor];
7         }
8     }];
9
10  [self.bgView setBackgroundColor:dyColor];

效果展示

%title插图%num
2 图片适配

%title插图%num
打开Assets.xcassets
新建一个Image set

打开右侧工具栏,点击*后一栏,找到Appearances,选择Any,Dark

%title插图%num

将两种模式下不同的图片资源都拖进去

%title插图%num

使用该图片

1  [_logoImage setImage:[UIImage imageNamed:@”icon_logo”]];
%title插图%num

大功告成,完成了颜色和图片的Dark Mode适配。

获取当前模式(Light or Dark)
有时候我们需要知道当前处于什么模式,并根据不同的模式执行不同的操作 iOS13中CGColor依然只能表示单一的颜色通过调用UITraitCollection.currentTraitCollection.userInterfaceStyle获取当前模式

1 if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
2         [self.titleLabel setText:@”DarkMode”];
3     }
4     else {
5         [self.titleLabel setText:@”LightMode”];
6     }
7

3. 其他
1.监听模式切换
有时我们需要监听系统模式的变化,并作出响应
那么我们就需要在需要监听的viewController中,重写下列函数

1 // 注意:参数为变化前的traitCollection
2 – (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection;
3
4 // 判断两个UITraitCollection对象是否不同
5 – (BOOL)hasDifferentColorAppearanceComparedToTraitCollection:(UITraitCollection *)traitCollection;
6

① 示例

1 – (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
2     [super traitCollectionDidChange:previousTraitCollection];
3     // trait发生了改变
4     if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
5     // 执行操作
6     }
7     }
8

2.CGColor适配
我们知道iOS13后,UIColor能够表示动态颜色,但是CGColor依然只能表示一种颜色,那么对于CALayer等对象如何适配暗黑模式呢?当然是利用上一节提到的监听模式切换的方法啦。

① 方式一:resolvedColor

1 // 通过当前traitCollection得到对应UIColor
2 // 将UIColor转换为CGColor
3 – (UIColor *)resolvedColorWithTraitCollection:(UITraitCollection *)traitCollection;

实例

1 – (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
2     [super traitCollectionDidChange:previousTraitCollection];
3
4     UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
5         if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
6             return [UIColor redColor];
7         }
8         else {
9             return [UIColor greenColor];
10         }
11     }];
12     UIColor *resolvedColor = [dyColor resolvedColorWithTraitCollection:previousTraitCollection];
13     layer.backgroundColor = resolvedColor.CGColor;
14

② 方式二:performAsCurrent

1 // 使用当前trainCollection调用此方法
2 – (void)performAsCurrentTraitCollection:(void (^)(void))actions;

示例

1 – (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
2     [super traitCollectionDidChange:previousTraitCollection];
3
4     UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
5         if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
6             return [UIColor redColor];
7         }
8         else {
9             return [UIColor greenColor];
10         }
11     }];
12     [self.traitCollection performAsCurrentTraitCollection:^{
13         layer.backgroundColor = dyColor.CGColor;
14     }];
15
16 }
17

方式三:*简单的方法
直接设置为一个动态UIColor的CGColor即可

1 – (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
2     [super traitCollectionDidChange:previousTraitCollection];
3     UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
4         if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
5             return [UIColor redColor];
6         }
7         else {
8             return [UIColor greenColor];
9         }
10     }];
11         layer.backgroundColor = dyColor.CGColor;
12 }
13
14

⚠️!!! 设置layer颜色都是在traitCollectionDidChange中,意味着如果没有发生模式切换,layer将会没有颜色,需要设置一个基本颜色

3.模式切换时打印log
在Xcode菜单栏Product->Scheme->Edit Scheme
选择Run->Arguments->Arguments Passed On Launch
添加以下命令即可
UITraitCollectionChangeLoggingEnabled YES

%title插图%num

4.强行设置App模式
当系统设置为Light Mode时,对某些App的个别页面希望一直显示Dark Mode下的样式,这个时候就需要强行设置当前ViewController的模式了

1 // 设置当前view或viewCongtroller的模式
2 @property(nonatomic) UIUserInterfaceStyle overrideUserInterfaceStyle;

示例

1 // 设置为Dark Mode即可
2 [self setOverrideUserInterfaceStyle:UIUserInterfaceStyleDark];

⚠️ 注意!!!

当我们强行设置当前viewController为Dark Mode后,这个viewController下的view都是Dark Mode
由这个ViewController present出的ViewController不会受到影响,依然跟随系统的模式
要想一键设置App下所有的ViewController都是Dark Mode,请直接在Window上执行overrideUserInterfaceStyle
对window.rootViewController强行设置Dark Mode也不会影响后续present出的ViewController的模式
5.NSAttributedString优化
对于UILabel、UITextField、UITextView,在设置NSAttributedString时也要考虑适配Dark Mode,否则在切换模式时会与背景色融合,造成不好的体验

推荐的做法

1 // 添加一个NSForegroundColorAttributeName属性
2 NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor labelColor]};
3 NSAttributedString *str = [[NSAttributedString alloc] initWithString:@”富文本文案” attributes:dic];
4
5

总结
总的来说,iOS13主要有以下变化:
1.支持 Dark Mode
2.UIColor变为动态颜色
3.更新StatusBar样式
4.更新UIActivityIndicatorView样式

iOS开发学习路线

初级iOS开发
iOS中级开发说白了,就是你学会了基本的UI界面搭建,上架,沉淀一段时间,你觉得自己还适合这门行业,还适合,还能接受 这个所谓的iOS开发工程师的行业.你就可以说是一名中级iOS开发.
这个沉淀时间 大约在1年的实际工作中,就可以完成.
如果你觉得这门行业不适合你,请仔细结合自身情况,是否转另一门计算机语言,还是彻底转行.
是否了解AFNetworking 的实现原理
是否了解SDAutolayout/Masonry 一种布局库的原理
是否能够处理基本的iOS崩溃原因/无法编译原因/无法上架原因?
是否拥有了一定的工作效率,稳定的工作效率.(而不是说,上面派了一个活下来,忙都忙不完,天天加班,还一堆bug)
是否能够处理第三方库引起的崩溃.
是否可以很好的融入工作环境,完成每一阶段的工作指标,而不会让自己疲惫不堪.
Xcode的使用
第三方库的灵活使用
AFN
MJRefresh
各种网站的使用
说明:作为一名初级的iOS开发,你需要具备以下技能
必备技能(全部都会的情况下查看下一项)
如何判断是否可以升阶
结论

中级iOS开发
如何判断是否可以升阶
结论
应用的内存处理
应用的推送处理
应用的模块化/单元测试
应用的第三方集成/集中化管理/稳定迭代
阅读强大的第三方源码/拥有快速上手新的第三方库的能力.
能够接受各种新功能的开发(这里是指,即使你没有做过,但是你仍然可以凭借着学习,解决任何业务需求:例如:蓝牙.AR.摄像头.硬件交互.等)
清楚明白数据的传递方式,应用与后台如何交换数据,交换数据的过程,结果,格式.
多线程的灵活使用.
各种并发事件的处理/以及界面的合理性/流畅度
设计模式的灵活使用.
说明:作为一名中级的iOS开发,你需要具备以下技能
必备技能(全部都会的情况下查看下一项)

高级iOS开发
应用的组件化/架构分层
数据结构,操作系统,计算机网络都有自己的了解和认知
Shell脚本/python/Ruby/JS 至少会一种.
说明:作为一名高级的iOS开发,你需要具备以下技能(我不是高级开发,所以这里只能给你们提供建议.)
必备技能

详细学习路线
学习路线
简介
这里只简单阐述一些概念性的东西,以及学习路线规划,真正的知识请从iOS基础知识点往下开始看.
Objective-C
介绍
概念
编译原理
程序启动原理
结束程序.
监听系统事件
Info.plist
.pch
App组成
打开程序
执行main函数
执行UIApplicationMain函数
初始化UIApplication(创建设置代理对象,开启事件循环)
语法.(此处定义可能略失严谨,口头教学为主)
基础语法
对象.
属性
数据类型
方法
继承
Frame/CGRect/CGPoint和CGSize
内存(针对MRC下情况进行介绍)
ARC/MRC
弱引用/强引用
Assign,retain,copy,strong
import 和@class的区别
Xcode使用
首先是针对Xcode菜单栏,希望自己可以去翻译一下每个菜单里每项功能的英文都是什么意思,有助于自己熟悉并加深印象的使用Xcode.
熟悉Xcode的各个功能.
UIKit控件.
界面分析(下载App进行学习).
界面适配
在这里推荐有兴趣的开发人员,下载并分析,AppStore中的每项分类的top50的应用,多学习大公司以及流行应用是如何开发应用的,其中流行的,新颖的开发界面的方式可以总结下来,猜想在大应用中,别的程序员是如何开发的.
代码架构.
代码架构文章推荐:https://casatwy.com/iosying-yong-jia-gou-tan-kai-pian.html
各种工具、第三方的使用.
其实每个项目的建立都大致分为:项目框架搭建,原生界面搭建,嵌入第三方库.有很多功能都会用到第三方库,大多数第三方库都是本着快速开发,完整功能实现的目的存在的.需要开发人员能够根据业务逻辑不同,选择*好*优质的第三方库进行使用.
代码封装
当使用较多第三方库后,要求开发人员学习其开发特点,以及其封装手法,运用在自己的项目上,封装自己的代码.灵活运用.
完整项目.
开发技巧
个人心得

iOS基础知识点
iOS基础知识点
如何学习iOS
开始涉猎不止于iOS领域中的知识,会去了解相关职位的基础知识,例如前端和后台或者服务器运维,或者项目相关知识,具体往自己的职业规划靠拢
多看开源或者注明的第三方库.
收藏并阅读各种大神的博客或者论坛.
开始考虑项目中的细节优化,内存处理和耗电情况
打好基础,学习OC中各种常用语法.
学习如何上架,上架会因为什么被拒,了解App上架规则.
多学习官方说明文档.
刚刚入门(如何学习)
刚刚入职1年(如何稳定)
入职3年(如何进阶)
框架的学习
AFNetworking
SDAutoLayout
YYKit
SDWebImage
MJRefresh
MJExtension
Bugly
Qiniu
Masonry
TZImagePickerController
Hyphenate_CN
第三方框架
苹果自带框架
基础UI控件
UILabel 标题栏
UIButton 按钮
UIImageView 图片视图
UITextField 文本输入框
UITextView 文本展示视图
UIProgressView 进度条
UISlider 滑动开关
UIGesture 手势
UIActivityIndicator 菊花控件
UIAlertView(iOS8废除) 警告框
UIActionSheet(iOS8废除) 操作表单
UIAlertController(iOS8出现) 警告视图控制器
UIScrollView 滚动视图
UIPageControl 页面控制器
UISearchBar 搜索框
UITableView 表视图
UICollectionView集合视图
UIWebView网页浏览器
UISwitch开关
UISegmentControl选择按钮
UIPickerView选择器
UIDatePicker日期选择器
UIToolbar工具栏
UINavigationBar通知栏
UINavigationController通知视图控制器
UITabbarController选择视图控制器
UIImagePickerController相册
UIImage图片
Xcode的使用
内存监测
全局断点
全局搜索替换
界面适配
StoryBoard
界面预览
基础操作 状态栏
偏好设置
Xcode Source Control 源代码管理器
Xcode workSpace工作组
Xcode Scheme 计划
Xcode AutoLayout 约束
Xcode CoreData数据库
LLDB 断点调试
数据存储
沙盒存储
NSDictionary归档
NSUserDefault
CoreData
NSKeyedArchiver
SQLite
FMDB
plist
App生命周期
alloc
init
创建View
ViewDidLoad
ViewWillAppear
ViewDidAppear
ViewWillDisappear
ViewDidDisappear
视图将要消失 (做一些视图将要消失时的UI的处理)
视图已经消失 (做一些视图消失之后数据的处理)
viewDidDisappear销毁定时器
dealloc
didReceiveMemoryWarning
控制器生命周期
应用生命周期
开发者账号&上架流程
个人
公司
企业
https://www.jianshu.com/p/6601a241da8e
https://www.jianshu.com/p/7c98651d3532
https://www.jianshu.com/p/9b994a019ee6
文章推荐:
常用知识
响应链
异常捕捉
国际化
代码模块化
类别/扩展
iPad与iPhone的区别
静态库
内存管理
Quartz2D
真机调试
isKindOfClass 与 isMemberOfClass
Return/Break/Continue
Core Animation
CALayer
AutoLayout
KVC/KVO
谓词NSPredicate
帧动画
界面旋转+状态栏隐藏
plist文件
通信
NS系列
宏定义
视图层次
切换视图
深浅拷贝
对象序列化
写入文件
获取沙盒路径
翻转视图
延伸视图
九大基本数据类型
九宫格
坐标比较
UIColor 、CIColor和CGColor 之间的关系
画图
静态变量
tag值
延时执行方法

中级知识点
设计模式
UIScrollView/UITableView/UICollectionView 的嵌套
动态行高
通知/代理/block
程序启动原理
触摸事件/手势
图文混编
Runtime
NSRunLoop
GCD
ReactiveCocoa开发
3DTouch
界面渲染
Charles花瓶抓包
区分模拟器/真机项目
常用知识
Block
蓝牙/传感器
物理仿真器UIDynamic
通讯录获取
音频/视频/二维码
真机调试
苹果内购/广告
推送/远程推送
单例模式
多线程
网络请求
定位
源代码管理Git

iOS高级知识点
iOS高级知识点
Socket
XMPP
加密
MD5详解
Base64加密解密
RSA非对称加密
AES对称加密
音频
基础
Core Audio
Audio Toolbox
OpenAL
AVFoundation
Speex语音聊天
AudioQueue/AudioSession
Speex简介
视频
AAC视频.H264推流
P2P传输
直播
RTMP协议
RTMP直播应用与延时分析
如果做一款inke版的App
推流发布和播放RTMP
FFmpeg
基于FFmpeg的推流器
HLS流媒体传输协议(HTTP Live Streaming)
FFmpeg
ijkPlayer
直播的技术分析与实现
算法
简介
冒泡排序
快速排序
插入排序
归并排序
二分查找
希尔排序
动态规划
堆排序

官方Kit
ARKit.
SiriKit
HealthKit
HomeKit
SearchKit
IOKit
PDFKit
CloudKit
GameplayKit
SpriteKit
SceneKit
MusicKit
ResearchKit
MapKit
StoreKit
AVKit

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速