Objective-C 语法完整学习手册(小白自学 + 开发备查)

文档定位:零基础自学、日常开发备查;每个语法模块:定义说明 → OC完整示例 → 等价JS/TS代码 → 语法详解 → 异同对比 → 常见坑

前置约定

  1. OC 依赖 Foundation 框架,所有示例默认 #import <Foundation/Foundation.h>

  2. OC:编译型、静态强类型;JS:解释型、动态弱类型;TS:JS超集,静态类型

  3. OC 集合严格区分 不可变 / 可变;JS Array / Object 默认可变

  4. OC 字符串前缀必须带 @;JS/TS 字符串直接引号包裹

目录

  1. 基础入门:日志打印

  2. 变量、常量、基础数据类型

  3. 运算符

  4. 流程控制:if / switch / for / while

  5. 字符串 NSString / NSMutableString 👉 对应 JS String

  6. 数组 NSArray / NSMutableArray 👉 对应 JS Array

  7. 字典 NSDictionary / NSMutableDictionary 👉 对应 JS Object

  8. 自定义类 & 对象(模型)👉 对应 JS Class

  9. 方法定义、调用(实例方法 - / 类方法 +)👉 对应 JS 函数

  10. 循环遍历全套写法对比

  11. Block vs JS 回调函数 / 箭头函数(OC高频难点)

  12. GCD(OC) vs JS Promise / async await 异步

  13. OC Protocol 协议 vs TS Interface / Type

  14. 内存、引用简单说明(小白够用版)


1. 基础入门:日志打印

定义

程序运行时输出文字、变量到控制台,用来查看数据、排查bug

OC

Objective-C 复制代码
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    // 1. 纯文本打印
    NSLog(@"Hello Objective-C");

    // 2. 占位符拼接变量
    NSString *name = @"小明";
    NSInteger age = 18;
    NSLog(@"姓名:%@,年龄:%ld", name, age);
    return 0;
}

OC常用占位符

%@ → 对象(字符串、数组、字典、自定义对象,万能)

%d → int 整数

%ld → NSInteger

%f → float / double 小数

JS

JavaScript 复制代码
// Node / 浏览器通用
const name = "小明";
const age = 18;
console.log("Hello JavaScript");
console.log(`姓名:${name},年龄:${age}`);

对比说明

  1. NSLog 自带时间戳、自动换行console.log 默认只输出内容

  2. OC 使用占位符拼接;JS 推荐模板字符串 ${变量}

避坑

OC 文字必须写 @"",写成 "" 会编译报错


2. 变量、常量、基础数据类型

定义

变量:存储空间,可以修改里面的值;常量:定义后不能修改

OC:声明必须写类型,类型一旦确定不能随意更换

JS:不用写类型,同一个变量可以存数字、字符串、布尔

OC

Objective-C 复制代码
#import <Foundation/Foundation.h>
int main() {
    // 常量 const:基础类型常量
    const int num = 100;

    // 1. 整数
    NSInteger age = 18;
    int height = 175;

    // 2. 小数
    float f = 3.14f;
    double d = 3.1415926;

    // 3. 布尔 YES(真) / NO(假) 大写
    BOOL isBoy = YES;

    // 4. 字符
    char c = 'A';

    // 5. 万能对象指针 id(可以接收任意对象,慎用,失去类型校验)
    id any = @"随便存";
    NSLog(@"%@", any);
    return 0;
}

JS

JavaScript 复制代码
// const 常量,let 变量,var 旧写法不推荐
const num = 100;
let age = 18;
let f = 3.14;
let d = 3.1415926;
let isBoy = true;
let c = 'A';
let any = "随便存";
console.log(any);

对比说明

  1. OC 区分 int / NSIntegerNSInteger 会自动适配32/64位系统,开发优先用

  2. OC 布尔 YES/NO(大写);JS true/false(小写)

  3. OC 变量赋值不同类型 → 编译报错;JS 允许随意更换变量类型

避坑

基础类型不能直接放进OC数组/字典,需要包装成 NSNumber 对象


3. 运算符

算术、比较、逻辑运算符,语法大体一致,只列出差异点

OC

Objective-C 复制代码
#import <Foundation/Foundation.h>
int main() {
    int a = 10, b = 3;
    NSLog(@"加法 %d", a + b);
    NSLog(@"取模 %d", a % b);

    BOOL res = (a > 5 && b < 5); // && 并且,|| 或者,! 取反
    NSLog(@"%d", res);
    return 0;
}

JS

JavaScript 复制代码
let a = 10, b = 3;
console.log("加法", a + b);
console.log("取模", a % b);
let res = (a > 5 && b < 5);
console.log(res);

差异重点

  1. ==:OC 比较基础值;OC 对象比较不能用 ==,要用 isEqual:

  2. JS:== 会自动隐式转换;=== 严格相等(推荐)

避坑

OC:@"abc" == @"abc" 对比的是内存地址,不是文本内容!

正确写法:[@"abc" isEqual:@"abc"]


4. 流程控制 if / switch / for / while

4.1 if else 判断

OC
Objective-C 复制代码
NSInteger score = 85;
if (score >= 90) {
    NSLog(@"优秀");
} else if (score >= 60) {
    NSLog(@"及格");
} else {
    NSLog(@"不及格");
}
JS
JavaScript 复制代码
let score = 85;
if (score >= 90) {
    console.log("优秀");
} else if (score >= 60) {
    console.log("及格");
} else {
    console.log("不及格");
}

4.2 switch

OC
Objective-C 复制代码
NSInteger level = 2;
switch (level) {
    case 1:
        NSLog(@"一级");
        break;
    case 2:
        NSLog(@"二级");
        break;
    default:
        NSLog(@"其他");
        break;
}

OC 旧版本 switch 不能直接判断字符串;新版本可支持

JS
JavaScript 复制代码
let level = 2;
switch (level) {
    case 1:
        console.log("一级");
        break;
    case 2:
        console.log("二级");
        break;
    default:
        console.log("其他");
        break;
}

4.3 for 循环

OC
Objective-C 复制代码
for (int i = 0; i < 5; i++) {
    NSLog(@"i = %d", i);
}
JS
JavaScript 复制代码
for (let i = 0; i < 5; i++) {
    console.log("i =", i);
}

4.4 while / do while

OC
Objective-C 复制代码
int i = 0;
while (i < 3) {
    NSLog(@"while i=%d", i);
    i++;
}
JS
JavaScript 复制代码
let i = 0;
while (i < 3) {
    console.log("while i=", i);
    i++;
}

对比说明

语法几乎一样;区别在条件判断:

OC 条件必须是明确 BOOL YES/NO ,不会自动隐式转布尔

JS 自动隐式转换:0、""、null、undefined 自动视为 false


5. 字符串 NSString / NSMutableString 👉 JS String

定义

  • NSString不可变字符串,创建后文字不能修改,只能读取、拼接生成新字符串

  • NSMutableString可变字符串,可以原地追加、删除、替换文本

  • JS String:字符串原始值,JS 字符串本身不可变,修改都会生成新字符串

OC

Objective-C 复制代码
#import <Foundation/Foundation.h>
int main() {
    // 不可变 NSString
    NSString *str1 = @"Hello";
    // 拼接(返回新字符串,原字符串不变)
    NSString *str2 = [str1 stringByAppendingString:@" World"];
    NSLog(@"%@", str2);

    // 可变 NSMutableString
    NSMutableString *mStr = [NSMutableString stringWithString:@"Hello"];
    [mStr appendString:@" World"]; // 追加
    [mStr replaceOccurrencesOfString:@"World" withString:@"OC" options:0 range:NSMakeRange(0, mStr.length)];
    NSLog(@"%@", mStr);
    return 0;
}

JS

JavaScript 复制代码
let str1 = "Hello";
let str2 = str1 + " World";
console.log(str2);
// JS 没有可变字符串,如需频繁拼接推荐数组join
let arr = ["Hello"];
arr.push(" World");
let mStr = arr.join("");
console.log(mStr);

常用方法对照

功能 OC JS
获取长度 str.length str.length
字符串拼接 stringByAppendingString + / 模板字符串
是否包含 str containsString:@"xx" str.includes("xx")
截取 substringWithRange slice / substring

避坑

NSString 不能用 appendString,调用会崩溃;频繁文本修改请使用 NSMutableString


6. 数组 NSArray / NSMutableArray 👉 JS Array

定义

  • NSArray:不可变数组,初始化完成后不能增删改元素,只能读取

  • NSMutableArray:可变数组,可以新增、删除、替换元素

⚠️ OC 数组只能存放对象 ,基础数字需要包装成 @10(NSNumber)

JS 数组:不限类型,数字、字符串、对象、数组都可以存放,默认可变

OC

Objective-C 复制代码
#import <Foundation/Foundation.h>
int main() {
    // 1. 不可变数组 NSArray(字面量写法推荐)
    NSArray *arr = @[@"苹果", @"香蕉", @100];
    NSLog(@"取值:%@", arr[0]);
    NSLog(@"数组长度:%ld", arr.count);

    // 2. 可变数组 NSMutableArray
    NSMutableArray *mArr = [NSMutableArray array];
    [mArr addObject:@"西瓜"]; // 末尾新增
    [mArr insertObject:@"橙子" atIndex:0]; // 指定下标插入
    mArr[1] = @"葡萄"; // 修改下标元素
    [mArr removeObjectAtIndex:0]; // 删除下标
    [mArr removeAllObjects]; // 清空数组
    return 0;
}

JS

JavaScript 复制代码
// JS 数组默认可变,无原生不可变数组
const arr = ["苹果", "香蕉", 100];
console.log("取值:", arr[0]);
console.log("数组长度:", arr.length);

const mArr = [];
mArr.push("西瓜");
mArr.splice(0, 0, "橙子");
mArr[1] = "葡萄";
mArr.splice(0, 1);
mArr.length = 0; // 清空

数组遍历对照

Objective-C 复制代码
// OC 快速遍历
for (id item in arr) {
    NSLog(@"%@", item);
}
JavaScript 复制代码
for (const item of arr) {
    console.log(item);
}

避坑

  1. NSArray 调用 addObject → 运行崩溃,必须 NSMutableArray

  2. 下标越界直接闪退,JS 越界返回 undefined


7. 字典 NSDictionary / NSMutableDictionary 👉 JS Object

定义

  • NSDictionary:不可变键值对,创建完成不能增删改

  • NSMutableDictionary:可变键值对,支持新增、删除、修改key-value

⚠️ OC key、value 都必须是对象 ,常用 NSString 做key

JS Object:key 自动转为字符串,value 任意类型

OC

Objective-C 复制代码
#import <Foundation/Foundation.h>
int main() {
    // 不可变字典
    NSDictionary *dict = @{
        @"name": @"小明",
        @"age": @18
    };
    NSString *name = dict[@"name"];
    NSLog(@"%@", name);

    // 可变字典
    NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
    mDict[@"gender"] = @"男"; // 新增/覆盖
    [mDict removeObjectForKey:@"gender"]; // 删除key
    mDict removeAllObjects; // 清空
    return 0;
}

JS

JavaScript 复制代码
const dict = {
    name: "小明",
    age: 18
};
const name = dict.name;
console.log(name);

const mDict = {};
mDict.gender = "男";
delete mDict.gender;
Object.keys(mDict).forEach(k => delete mDict[k]);

字典遍历

Objective-C 复制代码
for (NSString *key in dict) {
    id val = dict[key];
    NSLog(@"key:%@ val:%@", key, val);
}
JavaScript 复制代码
for (const key in dict) {
    const val = dict[key];
    console.log(`key:${key} val:${val}`);
}

避坑

OC 取值不存在key 返回 nil,JS 返回 undefined


8. 自定义类 & 对象(模型)👉 JS Class

定义

OC:采用 .h(声明) + .m(实现) 文件分离;@property 定义属性

JS:ES6 class 语法糖,单文件,无声明实现分离

OC 完整示例

Person.h
Objective-C 复制代码
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
// 自定义构造方法
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;
- (void)sayHello;
@end
Person.m
Objective-C 复制代码
#import "Person.h"
@implementation Person
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age {
    self = [super init];
    if (self) {
        self.name = name;
        self.age = age;
    }
    return self;
}
- (void)sayHello {
    NSLog(@"我叫%@,%ld岁", self.name, self.age);
}
@end
main 使用
Objective-C 复制代码
Person *p = [[Person alloc] initWithName:@"小红" age:20];
[p sayHello];

JS 等价 Class

JavaScript 复制代码
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayHello() {
        console.log(`我叫${this.name},${this.age}岁`);
    }
}
const p = new Person("小红", 20);
p.sayHello();

对比说明

  1. OC .h 控制对外暴露接口,天然封装;JS 无原生私有属性

  2. OC 创建对象:alloc 分配内存 + init 初始化

  3. OC 属性修饰符 nonatomic/copy/assign/strong 用来管理内存,JS 无需关心


9. 方法定义、调用(实例方法 - / 类方法 +)👉 JS 函数

定义

  • - 开头:实例方法,必须创建对象后调用

  • + 开头:类方法,直接用类名调用,无需实例化

OC 没有独立全局函数,方法全部依附类;JS 支持独立函数

OC

Objective-C 复制代码
// .h
@interface Demo : NSObject
+ (void)classFunc; // 类方法
- (void)instanceFunc:(NSString *)msg; // 实例方法,带参数
@end

// .m
@implementation Demo
+ (void)classFunc {
    NSLog(@"这是类方法");
}
- (void)instanceFunc:(NSString *)msg {
    NSLog(@"实例方法,参数:%@", msg);
}
@end

// 调用
[Demo classFunc];
Demo *d = [[Demo alloc] init];
[d instanceFunc:@"测试消息"];

JS

JavaScript 复制代码
// 独立函数(OC没有等价全局方法)
function globalFunc() {
    console.log("全局函数");
}
globalFunc();

class Demo {
    static classFunc() { // static 静态方法 ≈ OC +类方法
        console.log("这是静态方法");
    }
    instanceFunc(msg) {
        console.log("实例方法,参数:", msg);
    }
}
Demo.classFunc();
const d = new Demo();
d.instanceFunc("测试消息");

对比说明

OC 调用语法:[对象 方法:参数] 消息发送机制

JS:对象.方法()


10. 循环遍历全套写法对比(备查)

汇总多种遍历方式,开发查阅使用

Objective-C 复制代码
NSArray *arr = @[@"A", @"B", @"C"];
// 1. 传统for循环
for (int i = 0; i < arr.count; i++) {
    NSLog(@"下标%d:%@", i, arr[i]);
}
// 2. forin 快速遍历
for (id obj in arr) {
    NSLog(@"元素:%@", obj);
}
// 3. Block回调遍历(重点,和下一章联动)
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    NSLog(@"下标%lu 值%@", idx, obj);
}];
JavaScript 复制代码
const arr = ["A","B","C"];
// 1. 传统for
for(let i = 0; i < arr.length; i++){
    console.log(`下标${i}:`, arr[i]);
}
// 2. for of
for(const item of arr){
    console.log("元素:", item);
}
// 3. forEach 回调遍历
arr.forEach((item, idx)=>{
    console.log(`下标${idx} 值${item}`);
})

11. Block vs JS 回调函数 / 箭头函数(OC高频难点 · 备查重点)

定义

  • Block(OC):代码块,一段可保存、传递、延迟执行的代码;多用于回调、异步、遍历。等价 JS 回调/箭头函数

  • JS 回调函数:函数作为参数传递,等待时机执行;箭头函数为简写形式

核心共同点:函数可传参、延迟执行、捕获外部变量

核心差异:Block 涉及内存管理(__block、循环引用);JS 由GC自动回收

11.1 Block 基础语法 + JS 对照

OC Block 基础格式
Objective-C 复制代码
// 返回值(^block名称)(参数) = ^(参数){代码};
void (^myBlock)(NSString *) = ^(NSString *msg) {
    NSLog(@"Block收到消息:%@", msg);
};
// 调用
myBlock(@"Hello Block");
JS 普通回调函数
JavaScript 复制代码
const myFunc = function(msg) {
    console.log("回调收到消息:", msg);
}
myFunc("Hello Callback");
JS 箭头函数简写(工程常用)
JavaScript 复制代码
const myFunc = (msg) => {
    console.log("回调收到消息:", msg);
}
myFunc("Hello Callback");

11.2 Block 作为方法参数(网络回调经典场景)

OC
Objective-C 复制代码
#import <Foundation/Foundation.h>

- (void)requestDataWithCallback:(void (^)(NSString *result))callback {
    // 模拟异步耗时操作
    NSString *res = @"接口返回数据";
    callback(res);
}

// 使用
[self requestDataWithCallback:^(NSString *result) {
    NSLog(@"回调结果:%@", result);
}];
JS 等价写法
JavaScript 复制代码
function requestDataWithCallback(callback) {
    const res = "接口返回数据";
    callback(res);
}

requestDataWithCallback((result) => {
    console.log("回调结果:", result);
});

11.3 Block 捕获外部变量(重点难点)

OC 默认:值拷贝,无法直接修改外部基础变量
Objective-C 复制代码
int num = 10;
void (^block)(void) = ^{
    // num = 99; // 编译报错,默认只读
    NSLog(@"block读取num:%d", num);
};
num = 99;
block(); // 输出 10,捕获时拷贝快照
OC 使用 __block 允许修改外部变量
Objective-C 复制代码
__block int num = 10;
void (^block)(void) = ^{
    num = 99;
    NSLog(@"block读取num:%d", num);
};
num = 88;
block(); // 输出99
JS 对比:引用捕获,可直接修改
JavaScript 复制代码
let num = 10;
const func = () => {
    num = 99;
    console.log("回调读取num:", num);
};
num = 88;
func(); // 输出99

11.4 Block 循环引用(OC高频坑,JS一般不用手动处理)

ARC下 self 持有block,block内部强引用self → 循环引用,内存泄漏

✅ OC 解决方案:weakSelf

Objective-C 复制代码
__weak typeof(self) weakSelf = self;
self.testBlock = ^{
    NSLog(@"%@", weakSelf.name);
};

JS:GC自动处理循环引用,绝大多数场景无需手动解除

11.5 场景对照表

场景 OC Block JS 回调 / 箭头函数
数组遍历回调 enumerateObjectsUsingBlock forEach
网络请求完成回调 block参数 callback / then
UI动画完成回调 completion block 回调函数
排序比较器 sortedArrayUsingComparator array.sort
延迟执行 dispatch_after + block setTimeout

11.6 避坑清单

  1. Block 默认不能修改外部基础变量,修改需要 __block

  2. 成员变量保存的block,内部使用self必须weak,防止循环引用

  3. Block语法 ^ 容易遗漏,强类型校验严格

  4. JS箭头函数不绑定this;Block捕获self默认强引用

11.7 typedef 简化冗长Block声明(项目标准写法)

Objective-C 复制代码
// 定义别名
typedef void(^ResultCallback)(NSString *result);

- (void)getData:(ResultCallback)callback {
    callback(@"数据");
}

12. GCD(OC) vs JS Promise / async await 异步编程(备查重点)

定义

  • GCD(Grand Central Dispatch):苹果官方C实现多线程调度API,管理队列、线程、异步任务,搭配Block。

  • Promise:JS异步容器,存放异步结果,解决回调地狱;

  • async / await:Promise语法糖,扁平化异步代码,可读性更高。

核心映射关系

  1. GCD队列派发异步任务 ≈ JS Promise

  2. GCD串行队列 ≈ Promise链式 .then()

  3. GCD dispatch_group 等待全部并发完成 ≈ Promise.all()

  4. async/await ≈ GCD信号量同步等待(写法扁平化)

  5. 主队列 dispatch_get_main_queue() ≈ JS主线程回调

重要底层差异:

GCD 支持多核真正并行多线程 ;JS 为单线程事件循环,异步仅任务排队,无法多核并行计算。

12.1 基础异步执行(GCD async vs Promise)

OC GCD
Objective-C 复制代码
#import <Foundation/Foundation.h>

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();

dispatch_async(globalQueue, ^{
    NSLog(@"子线程:执行耗时操作(网络/文件)");
    sleep(1);
    
    // 切回主线程刷新UI
    dispatch_async(mainQueue, ^{
        NSLog(@"主线程:刷新UI");
    });
});
JS Promise
JavaScript 复制代码
function fetchData() {
    return new Promise((resolve) => {
        console.log("异步:执行耗时操作(网络/文件)");
        setTimeout(() => {
            resolve("请求结果");
        }, 1000);
    });
}

fetchData().then(res => {
    console.log("主线程:拿到结果,更新页面", res);
});

12.2 串行依次执行任务(串行队列 vs Promise then / async await)

场景:A完成后执行B,B完成后执行C

OC GCD 串行队列
Objective-C 复制代码
dispatch_queue_t serialQueue = dispatch_queue_create("com.demo.serial", DISPATCH_QUEUE_SERIAL);

dispatch_async(serialQueue, ^{
    NSLog(@"任务1");
    sleep(1);
});
dispatch_async(serialQueue, ^{
    NSLog(@"任务2");
    sleep(1);
});
dispatch_async(serialQueue, ^{
    NSLog(@"任务3");
});
JS Promise 链式调用
JavaScript 复制代码
function task(val, delay) {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(val);
            resolve();
        }, delay);
    })
}

task("任务1",1000)
.then(()=>task("任务2",1000))
.then(()=>task("任务3",0));
JS async await(推荐扁平化写法)
JavaScript 复制代码
async function runSerial() {
    await task("任务1",1000);
    await task("任务2",1000);
    await task("任务3",0);
}
runSerial();

12.3 并发执行多个任务,等待全部完成(dispatch_group vs Promise.all)

OC dispatch_group
Objective-C 复制代码
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);

dispatch_group_async(group, globalQueue, ^{
    sleep(1);
    NSLog(@"并发任务A");
});
dispatch_group_async(group, globalQueue, ^{
    sleep(2);
    NSLog(@"并发任务B");
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"所有并发任务执行完毕");
});
JS Promise.all
JavaScript 复制代码
const p1 = task("并发任务A", 1000);
const p2 = task("并发任务B", 2000);

Promise.all([p1, p2]).then(() => {
    console.log("所有并发任务执行完毕");
});

12.4 延迟执行(dispatch_after vs setTimeout)

OC
Objective-C 复制代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"延迟2秒执行");
});
JS
JavaScript 复制代码
setTimeout(()=>{
    console.log("延迟2秒执行");
},2000);

12.5 仅执行一次(dispatch_once vs JS闭包单例)

OC
Objective-C 复制代码
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    instance = [[self alloc] init];
});
JS
JavaScript 复制代码
let instance = null;
function getInstance(){
    if(!instance){
        instance = {};
    }
    return instance;
}

12.6 API对照表

功能 OC GCD JS
异步子线程执行 dispatch_async(globalQueue, block) new Promise / setTimeout
切回主线程 dispatch_async(mainQueue, block) .then / await 默认主线程
串行顺序执行 DISPATCH_QUEUE_SERIAL Promise then链 / async await
并发等待全部完成 dispatch_group + notify Promise.all
任意一个任务完成即返回 手动分组标记 Promise.race
延迟调度 dispatch_after setTimeout
代码只运行一次 dispatch_once 闭包缓存实例
同步阻塞等待 dispatch_group_wait / semaphore await(非阻塞主线程)

12.7 避坑清单

OC GCD
  1. UI操作必须在主队列执行,子线程刷新UI会崩溃异常

  2. dispatch_sync 同步派发极易引发死锁(串行队列同步派发自身队列)

  3. semaphore信号量慎用,容易阻塞线程

  4. 异步回调block依旧存在self循环引用风险,使用weakSelf

JS 异步
  1. JS单线程,大量同步计算会阻塞页面,无法多核并行运算

  2. async函数永远返回Promise

  3. Promise异常未写 .catch() 会抛出未捕获错误

  4. await 只能写在 async 函数内部

12.8 回调地狱说明

多层嵌套回调可读性差:

  • OC:多层Block嵌套 → 推荐dispatch_group、拆分方法

  • JS:多层回调嵌套 → 推荐 Promise / async await


13. OC Protocol 协议 vs TS Interface / Type 类型别名(备查重点)

定义

  • OC Protocol(协议) :一套方法声明契约,定义可选/必选方法,可声明属性,不提供实现;类遵循协议并实现对应方法。常用于delegate代理、解耦、面向接口编程。

  • TS Interface :描述对象结构、方法契约,约束属性与方法签名;类可使用 implements 实现接口。

  • TS Type Alias(type):类型别名,和Interface大部分场景互通,支持联合、交叉类型。

✅ 核心对应

  1. @protocolinterface

  2. <Protocol> 遵循协议 ≈ TS class implements interface

  3. @required 必实现 ≈ interface 非可选成员

  4. @optional 可选实现 ≈ interface ? 可选成员

  5. id<Protocol> 协议类型变量 ≈ TS 变量声明为接口类型

  6. 协议继承 @protocol P1 <P2>interface A extends B

⚠️ 关键差异

  1. OC Protocol 运行时保留信息,可 conformsToProtocol: 判断;TS接口编译后擦除,仅编译期校验

  2. OC协议主要约束方法;TS Interface同时约束属性和方法

  3. 原生JS没有接口能力,仅能注释人工约定,无编译校验

13.1 最简示例:定义协议 / 接口

OC Protocol

Objective-C 复制代码
// 定义协议
@protocol UserProtocol <NSObject>
// @required 默认开启,可以省略
- (NSString *)getUserName;
- (void)sayHi;

// @optional 可选实现
@optional
- (void)doSomething;
@end

// 类遵循协议 <>
@interface User : NSObject <UserProtocol>
@end

@implementation User
- (NSString *)getUserName {
    return @"小明";
}
- (void)sayHi {
    NSLog(@"Hi!");
}
// doSomething 可选,允许不实现
@end

TS Interface 等价

TypeScript 复制代码
interface UserProtocol {
    getUserName(): string;
    sayHi(): void;
    doSomething?(): void; // ? 等价 @optional
}

class User implements UserProtocol {
    getUserName(): string {
        return "小明";
    }
    sayHi(): void {
        console.log("Hi!");
    }
}

TS Type 别名等价

TypeScript 复制代码
type UserProtocol = {
    getUserName: () => string;
    sayHi: () => void;
    doSomething?: () => void;
};

原生 JS(注释模拟,无编译校验)

JavaScript 复制代码
/**
 * @typedef {Object} UserProtocol
 * @property {()=>string} getUserName
 * @property {()=>void} sayHi
 * @property {(()=>void)|undefined} [doSomething]
 */
class User {
    getUserName() { return "小明"; }
    sayHi() { console.log("Hi!"); }
}

13.2 协议作为参数类型(id)

OC

Objective-C 复制代码
void printUser(id<UserProtocol> user) {
    NSLog(@"%@", [user getUserName]);
}

id<UserProtocol> u = [[User alloc] init];
printUser(u);

TS

TypeScript 复制代码
function printUser(user: UserProtocol) {
    console.log(user.getUserName());
}
const u: UserProtocol = new User();
printUser(u);

13.3 协议继承扩展

OC

Objective-C 复制代码
@protocol BaseProtocol <NSObject>
- (void)baseFunc;
@end

@protocol SubProtocol <BaseProtocol>
- (void)subFunc;
@end

@interface Demo : NSObject <SubProtocol>
@end

TS interface extends

TypeScript 复制代码
interface BaseProtocol {
    baseFunc(): void;
}
interface SubProtocol extends BaseProtocol {
    subFunc(): void;
}
class Demo implements SubProtocol {
    baseFunc(): void {}
    subFunc(): void {}
}

13.4 经典场景:Delegate 代理模式(iOS高频用法)

OC 完整示例

Objective-C 复制代码
@protocol DataLoaderDelegate <NSObject>
- (void)onLoadSuccess:(NSString *)result;
@optional
- (void)onLoadFail:(NSError *)error;
@end

@interface DataLoader : NSObject
@property (nonatomic, weak) id<DataLoaderDelegate> delegate;
- (void)loadData;
@end

@implementation DataLoader
- (void)loadData {
    dispatch_async(dispatch_get_global_queue(0,0), ^{
        NSString *res = @"加载完成";
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self.delegate respondsToSelector:@selector(onLoadSuccess:)]) {
                [self.delegate onLoadSuccess:res];
            }
        });
    });
}
@end

@interface ViewController : NSObject <DataLoaderDelegate>
@end
@implementation ViewController
- (void)onLoadSuccess:(NSString *)result {
    NSLog(@"回调收到:%@", result);
}
@end

TS 等价实现

TypeScript 复制代码
interface DataLoaderDelegate {
    onLoadSuccess(result: string): void;
    onLoadFail?(error: Error): void;
}

class DataLoader {
    delegate?: DataLoaderDelegate;
    loadData() {
        setTimeout(() => {
            const res = "加载完成";
            this.delegate?.onLoadSuccess(res);
        }, 1000);
    }
}

class ViewController implements DataLoaderDelegate {
    onLoadSuccess(result: string): void {
        console.log("回调收到:", result);
    }
}

补充:现代JS/TS 更多使用Promise替代Delegate回调;iOS原生控件大量依赖Protocol Delegate

13.5 能力对比表

能力 OC @protocol TS interface TS type
定义方法契约
定义属性结构
继承扩展 <> ✅ extends ✅ &交叉类型
同名定义自动合并
联合/元组/基础类型包装
编译期类型校验 ❌(运行时)
运行时保留类型信息 ✅ conformsToProtocol ❌ 编译擦除

选型建议

  1. 对标OC协议、类实现契约、模块对外接口 → interface

  2. 联合类型、工具类型、简单别名 → type

13.6 避坑清单

OC Protocol

  1. delegate 属性必须使用 weak,防止循环引用内存泄漏

  2. 调用 optional 方法前必须 respondsToSelector: 判断,否则崩溃

  3. 协议声明property,类需要手动合成getter/setter

  4. 协议建议继承 <NSObject>,才能使用 conformsToProtocol:respondsToSelector:

TS Interface / Type

  1. TS接口编译后删除,运行时无法判断对象是否实现接口

  2. interface 支持声明合并,容易意外覆盖定义;type不支持合并

  3. implements 仅做编译约束,不会自动生成方法,必须手动实现全部必选成员

13.7 泛型协议简要对比

OC

Objective-C 复制代码
@protocol ResponseProtocol <NSObject>
- (void)handleData:(id)data;
@end

OC泛型能力偏弱,一般搭配泛型容器使用

TS 泛型接口

TypeScript 复制代码
interface ResponseProtocol<T> {
    handleData(data: T): void;
}

14. 内存、引用简单说明(小白够用版)

  1. OC:ARC 自动引用计数,对象使用 strong 强引用;引用计数归零自动释放;区分 copy / assign / weak 修饰符管理内存。

  2. JS/TS:自动垃圾回收 GC,开发者不需要手动管理内存释放。

  3. 值传递 vs 引用传递:

    • OC:基础类型值传递;对象传递指针(引用)

    • JS/TS:基础原始类型值传递;对象、数组为引用传递

  4. 常见内存问题:OC容易出现循环引用,需要手动weak;JS现代GC可自动处理绝大多数循环引用场景。


相关推荐
ambition202422 小时前
操作系统同步:读者-写者问题与读写公平法详解(附每个 PV 操作含义)
linux·开发语言·数据结构·unix
chuan.bai5 小时前
Java RAG 实战(第 11 篇):RAG 知识工作台网页
java·开发语言·人工智能
离陌在学C#8 小时前
C# 事件(Event)详解:从概念到实战
开发语言·c#
Terra.K8 小时前
Java异常学习[特殊字符]
java·开发语言·学习
葡萄城技术团队9 小时前
InfluxDB 2\.x 深度解析:核心架构、Flux 函数与制造业落地指南(三)
java·开发语言·架构
counting money10 小时前
Java IO流详解:从InputStream到文件操作实战
java·开发语言·python
wuyk55510 小时前
98.C语言易混难点:字符数组与字符串指针的底层差异
c语言·开发语言·c++·stm32·嵌入式硬件·算法
峥无10 小时前
从0到1手撕红黑树:封装实现 my_map 与 my_set(SGI-STL 源码级深度解析)
开发语言·c++·笔记·算法·stl
波特率11520010 小时前
C++新特性---属性说明符与标准属性
开发语言·c++