0%

homebrew简介

homebrew类似于QQ软件管家,方便我们安装卸载第三方软件。当然这里的软件指的是命令行软件,而不是我们通常使用的应用软件。

安装homebrew

1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

通过homebrew安装的软件目录位置

1
/usr/local/Cellar

/usr/local/bin目录下的文件则是Cellar下对应软件的一个快捷访问。

homebrew使用

1.安装软件

1
brew install xxx
阅读全文 »

node简介

Node.js 是能够在服务器端运行JavaScript 的开放源代码、跨平台执行环境。Node.js 由 OpenJS Foundation 持有和维护,亦为Linux 基金会的项目。Node.js 是一个开源的跨平台 JavaScript 运行时环境,侧重于服务器端和网络应用。

Node.js 非常适合用于:

  • 使用 Node.js 开发的单页 Web 应用程序
  • Web 服务器后端
  • 移动和桌面应用程序(包括游戏)
  • 机器学习系统或 IoT 设备的后端

安装node

node版本是一个比较棘手的问题,比如6.3.0版的node跑不了一些新项目,升级到10.x版的node后,又跑不了旧项目。所以安装的node最好能方便切换版本。推荐先安装nvm,再使用nvm安装管理node版本。nvmNode.js 的版本管理工具,可以创建不同版本 Node 的隔离环境,从而避免不同版本包之间的干扰。

安装 nvm 之前最好是将现有的全局 Node 进行卸载,否则会发生冲突。

先查看一下node信息:

1
2
3
4
➜  ~ which node
/usr/local/bin/node
➜ ~ node -v
v21.6.1

之前是用homebrew安装的,可以通过brew list查看:

阅读全文 »

ssh类型的仓库,git clone/pull报错:kex_exchange_identification: Connection closed by remote host

1
2
3
4
5
6
7
git pull --verbose
kex_exchange_identification: Connection closed by remote host
Connection closed by 127.0.0.1 port 7890
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

这个报错其实跟使用梯子有关。

解决:

step 1.将~/.ssh下的id_rsa.pub(没有就先创建公私钥)公钥内容添加到github后台。

step 2.在~/.ssh/config文件(没有就先创建)中添加:

1
2
3
4
Host github.com
HostName ssh.github.com
User git
Port 443

上述内容表示ssh使用443端口而不再是默认的22。

step 3.使用命令ssh -T git@github.com验证

1
2
$ ssh -T git@github.com
Hi xq-120! You've successfully authenticated, but GitHub does not provide shell access.
阅读全文 »

什么是shell

看语境,有时候Shell指连接内核和用户的一个应用程序,有时候指一种脚本编程语言。不过这个看语境对于一个小白来说其实还挺难的,大部分情况下说shell其实说的是应用程序,但如果是说shell命令,脚本文件那shell就是指一种编程语言。

macOS 系统的默认终端(shell应用程序)是 Terminal,默认使用的shell是zsh(这里的zsh就是指脚本编程语言)。iTerm2 也是一款终端软件。iTerm2只是比Terminal拥有更多的自定义设置,使用oh-my-zsh美化后都差不多。终端这个shell应用程序可以设置具体使用哪一种shell作为默认shell。使用哪种shell作为默认shell的终端就称为xxx终端,比如zsh终端,bash终端。

Shell 可以指一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,它和 QQ、迅雷、Firefox 等其它软件没有什么区别。然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。

Shell 也可以指一种脚本编程语言。Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器(解释器一般就是shell终端软件也就是Terminal或者iTerm2等等)就可以了。

Shell 主要用来开发一些实用的、自动化的小工具,而不是用来开发具有复杂业务逻辑的中大型软件,例如检测计算机的硬件参数、搭建 Web 运行环境、日志分析等,Shell 都非常合适。

有哪些shell

shell是一个总称,具体shell有:bash、csh、ksh、zsh等等。Mac默认使用的是zsh。

查看安装了哪些shell:

1
cat /etc/shells
阅读全文 »

macOS目录命令

1.新建目录mkdir

语法:

1
mkdir [-p] dirName

-p: 如果中间目录不存在则创建一个。不加 -p 参数如果中间目录不存在则会报错:No such file or directory。

示例:

1
2
3
mkdir 文件名1
mkdir 文件名1 文件名2
mkdir -p 文件名/文件名

通常使用md较多,md是mkdir -p的别名。

2.删除文件rm

语法:

阅读全文 »

OC对象的内存布局

如下图

注:子类可以拥有和父类同名的实例变量,它们是相互独立的。

isa占用8个字节,是所有对象都拥有的。OC对象最少占用16字节,一些对象可能实际只使用了8个字节,但系统在分配内存时会补足到16字节。isa的offset是0,然后按照内存对齐规则,offset一直增加下去。

由于内存对齐的原因,实例变量在内存中的顺序可能会和我们的书写顺序不一致。个人猜测:编译器会尽量和书写顺序一致,再按照内存对齐规则调整。(所以最好就别猜实例变量的顺序了)

可以使用下面的函数打印offset:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static NSUInteger FBGetMinimumIvarIndex(__unsafe_unretained Class aCls) {
NSUInteger minimumIndex = 1;
unsigned int count;
Ivar *ivars = class_copyIvarList(aCls, &count);

if (count > 0) {
Ivar ivar = ivars[0];
ptrdiff_t offset = ivar_getOffset(ivar);
minimumIndex = offset / (sizeof(void *));
}

for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
ptrdiff_t offset = ivar_getOffset(ivar);
NSUInteger index = offset / (sizeof(void *));
NSLog(@"ivar:%s,offset:%td,index:%lu", ivar_getName(ivar), offset, index);
}

free(ivars);

return minimumIndex;
}

类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@interface FDEDog : NSObject

@property (nonatomic, strong) id property_1_s;
@property (nonatomic, weak) id property_2_w;
@property (nonatomic, unsafe_unretained) id property_3_un;
@property (nonatomic, weak) id property_4_w;
@property (nonatomic, strong) id property_5_s;
@property (nonatomic, strong) id property_6_s;
@property (nonatomic, unsafe_unretained) id property_7_un;
@property (nonatomic, strong) id property_8_s;
@property (nonatomic, strong) id property_9_s;
@property (nonatomic, weak) id property_10_w;
@property (nonatomic, weak) id property_11_w;
@property (nonatomic, strong) id property_12_s;
@property (nonatomic, assign) int property_13_int;
@property (nonatomic, assign) short property_14_short;
@property (nonatomic, weak) id property_15_w;
@property (nonatomic, assign) char property_16_char;
@property (nonatomic, strong) id property_17_s;

@end
阅读全文 »

流式读写数据,所谓流式就是像小溪流一样细水长流避免峰值影响。它可以让你避免一次性将数据加载到内存,从而导致内存暴涨。比如播放一个本地视频文件,你不需要先将整个视频都加载到内存再播放,而是读取一段播放一段。

系统提供了两个子类NSInputStream和NSOutputStream用于流式处理。NSInputStream用于流式读取数据,NSOutputStream用于流式写入数据。

NSInputStream

输入流,按次序从仓库读取数据。这个仓库可以是一个文件,一个NSData对象或者是一个网络socket。注意:网络socket输入流和前面两种输入流的初始化步骤是不一样的。

因为是读数据,所以仓库必须存在,比如如果仓库是一个文件,则该文件必须存在,否则会打开失败提升:

1
读错误:Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory" UserInfo={_kCFStreamErrorCodeKey=2, _kCFStreamErrorDomainKey=1}

read:maxLength:

1
2
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len;
// reads up to length bytes into the supplied buffer, which must be at least of size len. Returns the actual number of bytes read.

返回值说明:

阅读全文 »

实例对象、类与元类

实例对象的类称为类(类对象),类(类对象)的类称为元类(元类对象)。他们都是对象。

OC中对象、类和元类的关系如下图:

总结下:

  1. 实例对象的类是类对象,类对象的类是元类对象.元类对象的类是根元类,根元类对象的类就是自己本身.这里形成了一个闭环.

  2. 类对象里面保存的是实例方法.

  3. 元类对象里面保存的是类方法.

  4. 根类对象的superClass是nil,根类对象的类是根元类对象,根元类对象的superClass是根类对象,这里也形成了一个闭环.

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)test_class_metaClass {
//根类对象
NSLog(@"根类对象[NSObject class]:%@,地址:%p", [NSObject class], [NSObject class]);
//根类对象的父类
NSLog(@"根类对象的父类[[NSObject class] superclass]:%@,地址%p", [[NSObject class] superclass], [[NSObject class] superclass]);
const char *nsobjectClassChar = [NSStringFromClass([NSObject class]) UTF8String];
Class nsobjectMetaClass = objc_getMetaClass(nsobjectClassChar);
Class nsobjectMetaClass1 = object_getClass(NSObject.class); //nsobjectMetaClass与nsobjectMetaClass1相等。
//根类对象的类即根元类对象
NSLog(@"根类对象的类即根元类对象(NSObject metaClass):%@,地址:%p", nsobjectMetaClass, nsobjectMetaClass);
//根元类对象的父类
NSLog(@"根元类对象的父类(NSObject metaClass superclass):%@,地址:%p", [nsobjectMetaClass superclass], [nsobjectMetaClass superclass]);
//根元类对象的类
Class root = objc_getMetaClass([NSStringFromClass(nsobjectMetaClass) UTF8String]);
NSLog(@"根元类对象的类:%@,地址:%p", root, root);
}

打印:

1
2
3
4
5
2023-05-07 14:28:18.507417+0800 runtime方法使用Demo[20896:7290701] 根类对象[NSObject class]:NSObject,地址:0x1b9e44148
2023-05-07 14:28:18.507511+0800 runtime方法使用Demo[20896:7290701] 根类对象的父类[[NSObject class] superclass]:(null),地址0x0
2023-05-07 14:28:18.507599+0800 runtime方法使用Demo[20896:7290701] 根类对象的类即根元类对象(NSObject metaClass):NSObject,地址:0x1b9e440f8
2023-05-07 14:28:18.507663+0800 runtime方法使用Demo[20896:7290701] 根元类对象的父类(NSObject metaClass superclass):NSObject,地址:0x1b9e44148
2023-05-07 14:28:18.507762+0800 runtime方法使用Demo[20896:7290701] 根元类对象的类:NSObject,地址:0x1b9e440f8
阅读全文 »

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)test_class_superClass {
Person *per = [[Person alloc] init];
Class cls = [per class]; //Person
Class cls1 = [per superclass]; //Animal
Class cls2 = Person.self; //Person
Class cls3 = [Person class]; //Person
Class cls4 = [Person superclass]; //Animal
Class cls5 = object_getClass(per); //Person
Class cls6 = class_getSuperclass([Person class]); //Animal
Class cls7 = object_getClass([Person class]); //Person的元类
Class cls8 = class_getSuperclass(cls7); //Person元类的父类
Class cls9 = [cls7 superclass]; //Person元类的父类 等于cls8
}

获取对象的类

获取一个对象(实例对象或类对象)的类的核心方法就是object_getClass,实现:

1
2
3
4
5
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}

其实就是获取objc_object结构体里的isa字段的值。因此如果传入的是类对象,那么返回的将是类对象的类即元类。

实例方法class的实现就是调用object_getClass:

1
2
3
- (Class)class {
return object_getClass(self);
}

但是类方法class,并不是返回类对象的类,而是直接返回的自己。

1
2
3
4
5
6
7
+ (Class)class {
return self;
}

+ (id)self {
return (id)self;
}
阅读全文 »