深入 Objective-C:基于 learnxinyminutes-docs 的语法、对象模型与内存管理实战指南

发布时间:2026/10/10 2:31:27
深入 Objective-C:基于 learnxinyminutes-docs 的语法、对象模型与内存管理实战指南
文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载本篇以 learnxinyminutes-docs 仓库中的越南语版 vi/objective-c.md 为核心骨架融合英文原版 objective-c.md 的补充细节系统梳理 Objective-C 从程序骨架、类型系统、控制结构到类与对象、协议、分类Category、块Block与内存管理的完整知识图谱。读者读完将掌握 Objective-C 的语法全貌、消息传递的对象模型以及引用计数与 ARC 内存管理的实战写法可直接对照仓库中的可运行代码示例进行练习。Objective-C 是什么C 语言之上的 Smalltalk 式消息传递Objective-C 是苹果公司用于 macOS、iOS 操作系统及其框架 Cocoa 与 Cocoa Touch 的主要编程语言见 vi/objective-c.md 开篇引言。它是一门面向对象的通用编程语言其本质特征是在 C 语言的基础上加入了 Smalltalk 风格的消息传递messaging机制。这里的关键认知是Objective-C 不是简单地调用方法而是向对象实例发送消息。文档中用一个非常直白的例子说明了这一点// 创建对象实例先分配内存alloc再初始化init // 一个对象只有在 alloc 和 init 两步都完成后才真正可用 MyClass *myObject [[MyClass alloc] init]; // Objective-C 的面向对象模型基于消息传递 // 在 Objective-C 中你不是简单调用方法而是发送消息 [myObject instanceMethodWithParameter:Steve Jobs];这一模型贯穿了 Objective-C 的整个设计方法调用[receiver selector:argument]、Selector 的动态派发、Protocol 的接口约定都建立在消息这一抽象之上。程序骨架注释、导入、main 入口与日志输出注释与 #pragma markObjective-C 的注释语法继承自 C// 单行注释以 // 开头 /* 多行注释长这样。 */此外Xcode 支持#pragma mark指令来提升跳转栏jump bar的可读性为代码分组添加导航标签该细节来自英文原版 objective-c.md 第 22–24 行#pragma mark Navigation Functions // 在跳转栏新增名为 Navigation Functions 的标签 #pragma mark - Navigation Functions // 同样的标签前面多一条分隔线头文件导入与的区别与 import 模块使用#import导入头文件与 C 的#include不同#import会自动防止重复包含#import Foundation/Foundation.h // 用 导入全局文件一般是框架的头文件 #import MyClass.h // 用 导入本地文件来自当前项目用于导入框架framework中的全局头文件编译器在系统框架搜索路径中查找用于导入项目内的本地文件编译器优先在当前工程目录中查找。从 Xcode 5 开始对于 iOS ≥ 7.0 或 OS X ≥ 10.9 且启用了模块modules的项目还可以使用import语法直接导入框架编译更快且更安全见 objective-c.md 第 32–34 行import Foundation;main 入口、自动释放池与 NSLog程序入口是一个名为main、返回类型为int的函数int main (int argc, const char * argv[]) { // 创建自动释放池来管理程序内存 NSAutoreleasePool * pool [[NSAutoreleasePool alloc] init]; // 使用 NSLog() 向控制台输出 NSLog(Hello World!); // 打印字符串 Hello World! // ... 主体代码 ... // 释放你在程序中用到的内存 [pool drain]; // 结束程序 return 0; }两点说明对应 objective-c.md 第 40–43 行NSAutoreleasePool是手动引用计数MRC时代的产物[pool drain]会触发池内对象的自动释放如果使用自动引用计数ARC则用autoreleasepool { ... }块替代int main (int argc, const char * argv[]) { autoreleasepool { NSLog(Hello World!); // ... 其余代码 ... } return 0; }NSLog是 Objective-C 的日志输出函数格式占位符与 C 的printf类似但增加了面向对象的%占位符用于输出任意对象等价于调用该对象的description方法。类型与变量基本类型与对象声明强类型指针与 idC 的基本类型可以直接使用int myPrimitive1 1; long myPrimitive2 234554664565;对象声明遵循两条规则// 强类型对象声明在变量名前面加 *星号 MyClass *myObject1 nil; // 强类型Strong typing // 弱类型对象声明使用 id id myObject2 nil; // 弱类型Weak typingMyClass *是编译期强类型引用编译器知道该指针指向的具体类id是通用的对象指针类型可以指向任意 Objective-C 对象编译期不做类型检查nil是空对象指针向nil发送消息是安全的直接返回 nil/0。%占位符配合description方法展示对象值// % 表示一个对象 // description 是展示对象值的约定方法 NSLog(% and %, myObject1, [myObject2 description]); // 输出 (null) and (null)NSString 与 NSMutableString字符串字面量以前缀开头NSString *worldString World; NSLog(Hello %!, worldString); // 输出 Hello World!NSString是不可变字符串需要拼接、追加内容时使用可变的NSMutableString见 objective-c.md 第 67–70 行NSMutableString *mutableString [NSMutableString stringWithString:Hello]; [mutableString appendString: World!]; NSLog(%, mutableString); // 输出 Hello World!NSNumber 装箱字符、整数、浮点与 BOOL 字面量C 的基本类型不能直接放进集合NSArray 等需要装箱为NSNumber对象。现代写法用前缀的装箱字面量// 字符字面量 NSNumber *theLetterZNumber Z; char theLetterZ [theLetterZNumber charValue]; // 等价于 Z NSLog(%c, theLetterZ); // 整数字面量 NSNumber *fortyTwoNumber 42; int fortyTwo [fortyTwoNumber intValue]; // 等价于 42 NSLog(%i, fortyTwo); NSNumber *fortyTwoUnsignedNumber 42U; unsigned int fortyTwoUnsigned [fortyTwoUnsignedNumber unsignedIntValue]; NSLog(%u, fortyTwoUnsigned); NSNumber *fortyTwoShortNumber [NSNumber numberWithShort:42]; // 传统工厂方法 short fortyTwoShort [fortyTwoShortNumber shortValue]; NSLog(%hi, fortyTwoShort); NSNumber *fortyTwoLongNumber 42L; long fortyTwoLong [fortyTwoLongNumber longValue]; NSLog(%li, fortyTwoLong); // 浮点字面量 NSNumber *piFloatNumber 3.141592654F; float piFloat [piFloatNumber floatValue]; NSLog(%f, piFloat); // 输出 3.141592654 NSLog(%5.2f, piFloat); // 输出 3.14宽度与精度控制 NSNumber *piDoubleNumber 3.1415926535; double piDouble [piDoubleNumber doubleValue]; NSLog(%f, piDouble); NSLog(%4.2f, piDouble); // 输出 3.14 // BOOL 字面量 NSNumber *yesNumber YES; NSNumber *noNumber NO;传统写法如[NSNumber numberWithShort:42]工厂方法与42字面量等价字面量更简洁。英文原版还补充了无符号短整型、无符号长整型以及%5.2f/%4.2f宽度格式化的例子objective-c.md 第 86–111 行。NSDecimalNumber 定点数当浮点精度不够时如金融计算使用定点数类NSDecimalNumber见 objective-c.md 第 113–121 行NSDecimalNumber *oneDecNum [NSDecimalNumber decimalNumberWithString:10.99]; NSDecimalNumber *twoDecNum [NSDecimalNumber decimalNumberWithString:5.002]; // NSDecimalNumber 不能使用标准的 、-、*、/ 运算符它提供自己的方法 [oneDecNum decimalNumberByAdding:twoDecNum]; // 加 [oneDecNum decimalNumberBySubtracting:twoDecNum]; // 减 [oneDecNum decimalNumberByMultiplyingBy:twoDecNum]; // 乘 [oneDecNum decimalNumberByDividingBy:twoDecNum]; // 除 NSLog(%, oneDecNum); // 输出 10.99NSDecimalNumber 不可变容器对象NSArray、NSDictionary 与 NSSet集合类同样有不可变与可变两种形态且均可使用[...]、{...}字面量语法。NSArray数组——可以包含不同类型元素但必须是 Objective-C 对象NSArray *anArray [1, 2, 3, 4]; NSNumber *thirdNumber anArray[2]; // 下标访问 NSLog(Third number %, thirdNumber); // 输出 Third number 3 // 从 Xcode 7 开始NSArray 支持泛型类型标注 NSArrayNSString * *stringArray [hello, world]; // NSMutableArray 是可变的数组版本可增删元素 // 方便但效率不如 NSArray NSMutableArray *mutableArray [NSMutableArray arrayWithCapacity:2]; [mutableArray addObject:Hello]; [mutableArray addObject:World]; [mutableArray removeObjectAtIndex:0]; NSLog(%, [mutableArray objectAtIndex:0]); // 输出 WorldNSDictionary字典——键值对容器NSDictionary *aDictionary { key1 : value1, key2 : value2 }; NSObject *valueObject aDictionary[A Key]; // 按 key 取 value NSLog(Object %, valueObject); // 输出 Object (null)key 不存在时返回 nil // Xcode 7 起支持泛型 NSDictionaryNSString *, NSNumber * *numberDictionary {a: 1, b: 2}; // 可变的 NSMutableDictionary NSMutableDictionary *mutableDictionary [NSMutableDictionary dictionaryWithCapacity:2]; [mutableDictionary setObject:value1 forKey:key1]; [mutableDictionary setObject:value2 forKey:key2]; [mutableDictionary removeObjectForKey:key1];NSSet集合——自动去重的无序容器NSSet *set [NSSet setWithObjects:Hello, Hello, World, nil]; NSLog(%, set); // 输出 {(Hello, World)}顺序可能不同重复元素被去重 NSSetNSString * *stringSet [NSSet setWithObjects:hello, world, nil]; NSMutableSet *mutableSet [NSMutableSet setWithCapacity:2]; [mutableSet addObject:Hello]; [mutableSet addObject:Hello]; // 重复添加被忽略 NSLog(%, mutableSet); // 输出 {(Hello)}以上数组、字典、集合的完整示例均可在英文原版 objective-c.md 第 131–174 行找到。可变与不可变的转换copy 与 mutableCopy可变与不可变对象之间通过copy/mutableCopy转换见 objective-c.md 第 159–162 行// 一般而言[object mutableCopy] 得到可变副本[object copy] 得到不可变副本 NSMutableDictionary *aMutableDictionary [aDictionary mutableCopy]; // 不可变 - 可变 NSDictionary *mutableDictionaryChanged [mutableDictionary copy]; // 可变 - 不可变运算符运算符与 C 语言完全一致2 5; // 7 4.2f 5.1f; // 9.3f 3 2; // 0 (NO) 3 ! 2; // 1 (YES) 1 1; // 1逻辑与 0 || 1; // 1逻辑或 ~0x0F; // 0xF0按位取反 0x0F 0xF0; // 0x00按位与 0x01 1; // 0x02按位左移 1 位控制结构if-else 与 switch// If-Else 语句 if (NO) { NSLog(I am never run); } else if (0) { NSLog(I am also never run); } else { NSLog(I print); } // Switch 语句 switch (2) { case 0: { NSLog(I am never run); } break; case 1: { NSLog(I am also never run); } break; default: { NSLog(I print); } break; }注意在 Objective-C 中NO就是0YES就是1因此条件判断与 C 语义完全兼容。while、for 与快速枚举// While 循环 int ii 0; while (ii 4) { NSLog(%d,, ii); // ii 表示先使用值再自增 } // 输出 // 0, // 1, // 2, // 3, // For 循环 int jj; for (jj0; jj 4; jj) { NSLog(%d,, jj); } // 输出 0, 1, 2, 3, // Foreach快速枚举 fast enumeration NSArray *values [0, 1, 2, 3]; for (NSNumber *value in values) { NSLog(%,, value); } // 输出 0, 1, 2, 3, // 也可以使用 id 类型遍历任意对象集合见英文原版第 255–261 行 for (id item in values) { NSLog(%,, item); }try-catch-finally 异常处理与 NSError// Try-Catch-Finally 语句 try { // 你的语句 throw [NSException exceptionWithName:FileNotFoundException reason:Không Tìm Thấy Tập Tin trên Hệ Thống userInfo:nil]; } catch (NSException * e) // 用 catch (id exceptionName) 可以捕获所有对象 { NSLog(Exception: %, e); } finally { NSLog(Finally); } // 输出 Exception: Không Tìm Thấy Tập Tin trên Hệ Thống // Finally英文原版补充了NSError的用法——它是用于用户错误场景的惯例机制objective-c.md 第 278–279 行// NSError 对象通常作为函数参数传入用于填充用户错误信息 NSError *error [NSError errorWithDomain:Invalid email. code:4 userInfo:nil];对象与消息传递创建对象分两步先alloc分配内存再init初始化。两步完成前对象不可用// 通过分配内存并初始化来创建对象实例 MyClass *myObject [[MyClass alloc] init]; // 向对象发送消息等价于其他语言中的调用方法 [myObject instanceMethodWithParameter:Steve Jobs];Objective-C 的面向对象模型建立在向对象实例传递消息之上——在 Objective-C 中不是简单地调用方法而是发送消息。[receiver methodName:arg]这种方括号语法正是这一模型的直接体现。类与方法的完整生命周期interface 声明实例变量与 property类声明放在头文件如MyClass.h中声明语法为interface ClassName : ParentClassName ImplementedProtocols { type name; // 变量声明 } property type name; // 属性声明 -/ (type) Method declarations; // 方法声明 endinterface MyClass : NSObject MyProtocol { int count; id data; NSString *name; } // 便捷标记为公共访问变量自动生成 getter/setter property int count; property (copy) NSString *name; // (copy) 赋值时拷贝对象 property (readonly) id data; // (readonly) 只生成 getter外部不可赋值 // 方法声明 // 表示类方法 (NSString *)classMethod; // - 表示实例方法 - (NSString *)instanceMethodWithParameter:(NSString *)string; - (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number; end // 接口声明结束关于property的更多属性特性见英文原版 objective-c.md 第 317–331 行property int propInt;默认 getter 名为propIntsetter 名为setPropIntproperty (copy) id copyId;copy表示赋值时拷贝对象property (readonly) NSString *roString;readonly表示接口外不能赋值需在implementation中用synthesize生成访问器可自定义 getter/setter 名property (getterlengthGet, setterlengthSet:) int length;方法声明类方法与实例方法方法签名格式为/- (return type)methodSignature:(Parameter Type *)parameterName;。声明类方法可被类直接调用-声明实例方法必须由对象实例调用。Objective-C 的方法名极具描述性总是根据参数来命名如methodAParameterAsString:andAParameterAsNumber:这也是 Cocoa 命名规范的核心。implementation构造器、访问器与生命周期方法方法实现在实现文件MyClass.m中implementation MyClass // 对象被释放时调用 - (void)dealloc { } // 构造器是创建类实例的方式 // 这是对象初始化时调用的默认构造器 - (id)init { if ((self [super init])) // super 用于访问父类方法self 是对象自身 { self.count 1; } return self; } (NSString *)classMethod { return [[self alloc] init]; } - (NSString *)instanceMethodWithParameter:(NSString *)string { return New string; } - (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number { return 42; } // 在 MyProtocol 中声明的方法 - (void)myProtocolMethod { // 语句 } end // 实现结束英文原版还深入展示了访问变量、带参数构造器与initialize的用法objective-c.md 第 387–466 行implementation MyClass { long distance; // 实现文件中的私有实例变量 NSNumber *height; } // 访问接口文件中的实例变量使用 _ 加变量名 _count 5; // 引用 MyClass 接口中的 int count // 访问实现文件中定义的变量 distance 18; // 为 readonly 属性生成访问器变量 synthesize roString _roString; // _roString 现在可以在 implementation 中使用 // 在任何类方法或对象实例化之前调用一次 (void)initialize { if (self [MyClass class]) { distance 0; } } // 带参数的构造器 - (id)initWithDistance:(int)defaultDistance { distance defaultDistance; return self; }访问公共属性的完整流程setter/getter 自动生成、点语法与自定义访问器MyClass *myClass [[MyClass alloc] init]; [myClass setCount:10]; // 自动生成的 setter NSLog(%d, [myClass count]); // 输出 10自动生成的 getter [myClass lengthSet:32]; // 自定义 setter NSLog(%i, [myClass lengthGet]); // 输出 32自定义 getter // 点语法便捷写法 myClass.count 45; NSLog(%i, myClass.count); // 输出 45 // 调用类方法 NSString *classMethodString [MyClass classMethod]; // 调用实例方法 NSString *stringFromInstanceMethod [myClass instanceMethodWithParameter:Hello];Selector方法的动态表示Selector选择器是方法的动态表示方式用于在运行时调用类的方法、把方法作为参数传递、或将方法保存为变量objective-c.md 第 371–385 行// SEL 是选择器的数据类型selector() 根据方法名返回选择器 SEL selectorVar selector(methodAParameterAsString:andAParameterAsNumber:); if ([myClass respondsToSelector:selectorVar]) { // 检查类是否包含该方法 // 必须把所有方法参数放进一个对象再传给 performSelector NSArray *arguments [NSArray arrayWithObjects:Hello, 4, nil]; [myClass performSelector:selectorVar withObject:arguments]; // 调用该方法 } else { // NSStringFromSelector() 根据选择器返回方法名的字符串 NSLog(MyClass does not have method: %, NSStringFromSelector(selectorVar)); }这是 Objective-C 动态派发能力的体现方法可以在运行时被查找、传递和调用。Categories 分类在不继承的前提下扩展类分类Category是一组用于扩展已有类的方法。它允许你新增功能而非像子类那样改变功能并且可以为系统类如 NSString添加你自己的方法objective-c.md 第 468–572 行。// 一个简单的 Car 基类 interface Car : NSObject property NSString *make; property NSString *color; - (void)turnOn; - (void)accelerate; end // 基类实现 #import Car.h implementation Car synthesize make _make; synthesize color _color; - (void)turnOn { NSLog(Car is on.); } - (void)accelerate { NSLog(Accelerating.); } end如果只是给 Car 增加清洗功能就创建分类而不是子类。分类头文件命名约定为BaseClassNameCategoryName.h// 文件名CarClean.h #import Car.h // 必须导入要扩展的基类 interface Car (Clean) // 分类名写在括号内紧跟基类名 - (void)washWindows; // 新增方法声明 - (void)wax; end // 文件名CarClean.m #import CarClean.h implementation Car (Clean) - (void)washWindows { NSLog(Windows washed.); } - (void)wax { NSLog(Waxed.); } end任何 Car 实例只要导入该分类头文件就能使用分类方法#import CarClean.h #import Car.h int main (int argc, const char * argv[]) { autoreleasepool { Car *mustang [[Car alloc] init]; mustang.color Red; mustang.make Ford; [mustang turnOn]; // 使用基类方法 [mustang washWindows]; // 使用 Clean 分类的方法 } return 0; }重要注意事项原文档强调不要在分类中覆写基类方法即使技术上可行。覆写可能在不同分类之间引发编译错误也违背了分类只新增功能的初衷需要覆写时应使用子类。分类还可以用来模拟受保护方法把受保护的方法放进一个分类只在该类的implementation文件中导入该分类头文件类外部就无法访问这些方法objective-c.md 第 555–572 行。Extensions 扩展覆写属性与私有方法扩展Extension与分类语法相似interface Shape ()但它必须与类实现位于同一文件中用于覆写interface中的公共属性特性与方法或声明私有方法objective-c.md 第 574–609 行// 文件名Shape.h interface Shape : NSObject property (readonly) NSNumber *numOfSides; - (int)getNumOfSides; end // 文件名Shape.m #import Shape.h // 扩展与类实现放在同一个文件中 interface Shape () // 基类名后的 () 声明一个扩展 property (copy) NSNumber *numOfSides; // 把 numOfSides 从 readonly 改为 copy -(NSNumber)getNumOfSides; // 把返回类型改为 NSNumber -(void)privateMethod; // 在扩展中声明新的私有方法 end implementation Shape synthesize numOfSides _numOfSides; -(NSNumber)getNumOfSides { // 扩展中的声明必须在 implementation 中实现 return _numOfSides; } -(void)privateMethod { NSLog(Private method created by extension. Shape instances cannot call me.); } endGenerics 泛型Xcode 7从 Xcode 7.0 起可以创建泛型类在不写大量样板代码的前提下提供更强的类型安全与清晰度objective-c.md 第 611–654 行interface Result__covariant A : NSObject - (void)handleSuccess:(void(^)(A))success failure:(void(^)(NSError *))failure; property (nonatomic) A object; end // 声明实例 ResultNSNumber * *result; ResultNSArray * *result;每个泛型实例都等价于把接口中的类型参数A替换为对应类型。但需要注意Clang 不接受implementation中的泛型类型实现时必须使用idimplementation Result - (void)handleSuccess:(void (^)(id))success failure:(void (^)(NSError *))failure { // Do something } endProtocols 协议面向接口的约定协议声明任何类都可以实现的方法集合。协议本身不是类它只定义其他对象有责任实现的接口objective-c.md 第 657–727 行// 文件名CarUtilities.h protocol CarUtilities NSObject // NSObject 表示该协议包含的另一个协议 property BOOL engineOn; // 采纳协议的类必须 synthesize 所有 property - (void)turnOnEngine; // 并且实现所有方法 end // 实现该协议的类示例 #import CarUtilities.h interface Car : NSObject CarUtilities // 协议名写在 内 - (void)turnOnEngineWithUtilities:(id CarUtilities)car; // 协议也可以作为数据类型 end implementation Car : NSObject CarUtilities synthesize engineOn _engineOn; // 为 engineOn 属性创建 synthesize - (void)turnOnEngine { // 协议只要求实现方法不规定如何实现 _engineOn YES; } - (void)turnOnEngineWithCarUtilities:(id CarUtilities)objectOfSomeKind { [objectOfSomeKind engineOn]; // 可以访问协议定义的变量 [objectOfSomeKind turnOnEngine]; // 和协议定义的方法 } end协议使用时的三个关键惯例原文档强调// 1. 调用协议方法前先检查对象是否符合协议 Car *carInstance [[Car alloc] init]; if ([carInstance conformsToProtocol:protocol(CarUtilities)]) { NSLog(Car 实现了 CarUtilities 协议); } // 2. 分类也可以实现协议interface Car (CarCategory) CarUtilities // 3. 一个类可以实现多个协议interface Car : NSObject CarUtilities, CarCleaning当两个协议互相依赖时必须前向声明forward-declare否则编译器报错#import Brother.h protocol Brother; // 前向声明语句没有它编译器会报错 protocol Sister NSObject - (void)beNiceToBrother:(id Brother)brother; end // 问题在于 Sister 依赖 Brother而 Brother 也依赖 Sister #import Sister.h protocol Sister; // 这行停止递归解决问题 protocol Brother NSObject - (void)beNiceToSister:(id Sister)sister; endBlocks 块可作为数据的代码Block 是一段像函数一样的代码可以作为数据使用objective-c.md 第 729–758 行// 下面是一个简单的 block接收整数参数返回参数加 4 ^(int n) { return n 4; } int (^addUp)(int n); // 声明一个存储 block 的变量 void (^noParameterBlockVar)(void); // 无参数 block 的变量声明 // Block 可以访问同作用域中的变量但默认是只读的 // 传给 block 的值是 block 创建时变量的值 int outsideVar 17; // 如果在声明 addUp 之后修改 outsideVaraddUp 里仍是 17 __block long mutableVar 3; // __block 让变量对 block 可写 addUp ^(int n) { // 去掉 (int n) 可得到无参数 block NSLog(Block 里可以有任意多行语句。); NSSet *blockSet; // 也可以在 block 内声明局部变量 mutableVar 32; // 给 __block 变量赋新值 return n outsideVar; // return 语句是可选的 } int result addUp(10 16); // 带参数调用 block 代码Block 最常见的用途是作为函数参数供以后回调执行implementation BlockExample : NSObject - (void)runBlock:(void (^)(NSString))block { NSLog(Block 参数不返回值接收一个 NSString 对象。); block(传递给 block 执行的参数。); // 调用 block } end内存管理引用计数与 ARCMRC 手动引用计数Objective-C 不使用垃圾回收而是采用引用计数。只要对象至少有一个引用拥有该对象对象就可用引用计数归零时对象从内存中移除。每个对象交互都遵循创建 → 使用 → 释放的模式objective-c.md 第 761–806 行MyClass *classVar [MyClass alloc]; // alloc 把引用计数设为 1返回对象指针 [classVar release]; // 引用计数减 1 MyClass *newVar [classVar retain]; // retain 声明对已有对象的所有权引用计数加 1 // 即使 classVar 被 releasenewVar 仍持有对象 [classVar autorelease]; // 在 autoreleasepool 块结束时移除所有权property也可以使用retain和assign表示内存语义property (retain) MyClass *instance; // 释放旧值并 retain 新值强引用 property (assign) NSSet *set; // 只保存指针不 retain/release弱引用ARC 自动引用计数手动内存管理容易出错因此 Xcode 4.2 与 iOS 4 引入了 ARC。ARC 是编译器特性自动插入 retain、release 和 autorelease。使用 ARC 时严禁手动调用 retain、release、autoreleaseMyClass *arcMyClass [[MyClass alloc] init]; // ... 使用 arcMyClass 的代码 ... // 非 ARC 环境下用完需要调用 [arcMyClass release] // 使用 ARC 时无需手动调用编译器会自动插入 releaseARC 下property的属性用weak和strong替代assign和retainproperty (weak) MyClass *weakVar; // weak 不取得对象所有权 // 若原实例引用计数归零weakVar 自动变为 nil避免崩溃 property (strong) MyClass *strongVar; // strong 取得对象所有权保证对象在内存中可用对于普通变量非property声明的变量使用以下所有权修饰符__strong NSString *strongString; // 默认。变量在离开作用域前一直保留对象 __weak NSSet *weakSet; // 对已有对象的弱引用对象被释放时 weakSet 自动置 nil __unsafe_unretained NSArray *unsafeArray; // 类似 __weak但对象释放后不置 nil不安全仓库内进一步阅读learnxinyminutes-docs 仓库以代码即文档的形式维护了同一篇 Objective-C 教程的多语言版本可作为对照学习资源objective-c.md英文原版内容最完整包含#pragma mark、import模块、NSDecimalNumber、泛型、分类、扩展、Block 与内存管理等全部章节是本文细节的主要来源zh-cn/objective-c.md中文翻译版对每个代码片段有更详尽的逐句注释vi/objective-c.md越南语版即本文的核心骨架文档es/objective-c.md、fr/objective-c.md、ru/objective-c.md、tr/objective-c.md其他语言版本可用于多语言对照。建议的实践路径先按程序骨架 → 类型与变量 → 控制结构的顺序把main函数中的示例跑通再动手实现自己的interface/implementation类结合 Selector 与 Protocol最后通过分类、Block 与内存管理章节理解 Objective-C 区别于 C 的核心设计。文中所有代码均来自仓库文档原文可直接复制到 Xcode 工程中验证运行。赞分享文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载相关推荐learnxinyminutes-docs 之 C 语言完全指南从注释语法到指针与内存管理实战learnxinyminutes docs 之 C 语言完全指南从注释语法到指针与内存管理实战 本文以 learnxinyminutes docs 仓库中的意文档教程RDF 与 Turtle 语法实战指南基于 learnxinyminutes-docs 的语义网数据建模入门RDF 与 Turtle 语法实战指南基于 learnxinyminutes docs 的语义网数据建模入门 本篇技术指南以 learnxinyminutes文档教程Rust 全面入门实战指南基于 learnxinyminutes-docsja/rust.md的语法、所有权与内存安全深度解析Rust 全面入门实战指南基于 learnxinyminutes docsja/rust.md的语法、所有权与内存安全深度解析 本文以 learnxiny文档教程上一篇如何免费做出游戏精灵这款开源像素艺术编辑器三步搞定下一篇Mac Mouse Fix 实测普通鼠标如何在macOS上滚出触控板般顺滑创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考