很好的参考:https://www.runoob.com/w3cnote/objective-c-tutorial.html
Objective-C:C的超集
Objective-Objective-C是C语言的严格超集:任何C语言程序不经修改就可以直接通过Objective-C编译器
Objective-C被描述为盖在C语言上的薄薄一层
源代码的文件扩展名
- .h: 头文件
- .m: 源代码文件,更常用,可以包含 Objective-C 和 C 代码
- .mm: 源代码文件,可以包含 Objective-C 、 C 和 C++ 代码
#import和#include
- 你可以使用标准的 #include 编译选项
- #import 选项和 #include 选项完全相同,并且#import 可以确保相同的文件只会被包含一次
- Objective-C 的例子和文档都倾向于使用 #import
消息传递
Objective-C里,对象之间互相传递消息。
- C++里类别与方法的关系严格清楚,一个方法必定属于一个类别,而且在编译时(compile time)就已经紧密绑定,不可能调用一个不存在类别里的方法。
- Objective-C里,类别与消息的关系比较松散,调用方法视为对对象发送消息,所有方法都被视为对消息的回应。所有消息处理直到运行时(runtime)才会动态决定,并交由类别自行决定如何处理收到的消息。
类的声明
方法声明
参考:https://www.yiibai.com/objective_c/objective_c_functions.html
Objective-C编程语言中方法定义的一般形式如下
- (return_type) method_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen {
body of the function
}
示例:
/* 返回两个参数的最大值 */
- (int) max:(int) num1 secondNumber:(int) num2 {
/* 局部变量声明 */
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
方法调用
(1) 方括号语法(Bracket Syntax)
[object methodName];
[object methodNameWithArgument1:argument1 argument2:argument2];
[object methodName] 调用object对象的method方法
在 Objective-C语言里,方法和实现的关系不是在编译时决定的,而是在运行时决定的。
举例:
- (void) setColorToRed: (float)red Green: (float)green Blue:(float)blue; /* 声明方法*/
[myColor setColorToRed:1.0 Green:0.8 Blue:0.2]; /* 调用方法*/
(2) objc_msgSend 消息发送机制
是一种动态决议的间接调用方式
// 调用无参数方法
objc_msgSend(obj, "methodName");
// 调用有参数方法
objc_msgSend(obj, "methodNameWithArgument1:argument2:", argument1, argument2);
比如
objc_msgSend(v6, "addScriptMessageHandler:name:", self, CFSTR("windmill"));
含义是调用v6
这个对象的addScriptMessageHandler:name:
方法,方法的参数1是self
,参数2是CFSTR("windmill")
根据addScriptMessageHandler:name:
方法的定义:
(void)addScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
addScriptMessageHandler:name: 是 WKUserContentController 类的一个实例方法
- 参数1的类型是
id<WKScriptMessageHandler>
,参数名是scriptMessageHandler
,形参名称省略(第一个参数可以没有形参名称,后面的参数必须有形参名称;当然也可以理解为第一个参数的形参名称体现在了"methodNameWithArgument1"这个方法名里) - 参数2的类型是
NSString *
,参数名是name
,形参名称是name
协议
协议是一组没有实现的方法列表,类似Java中的"接口"
任何类都可以声明自身实现了某个协议
非正式协议与正式协议
- 非正式协议已经被废弃不再使用
- 正式协议中,一个类必须 实现它声明匹配的协议中的所有方法,否则编译器会报错
协议的语法
@protocol起始,@end结束,中间为方法列表
@protocol Locking
- (void)lock;
- (void)unlock;
@end
Delegate 委托机制
alloc 方法
OC中经常使用 NSObject *object = [[NSObject alloc] init];
这行代码去创建一个对象
通过对alloc底层源码的分析, 可以了解到:
① alloc的主要目的是开辟内存空间;
② 主要的核心逻辑是 计算内存大小->申请内存空间->绑定isa;
③ 计算内存大小是按照16字节对齐的。
参考:https://www.cnblogs.com/mysweetAngleBaby/p/16747295.html
IDA反编译看到的代码
bool __cdecl -[SpotifyAppDelegate application:openURL:options:](
_TtC24MusicApp_ContainerWiring18SpotifyAppDelegate *self,
SEL a2,
id a3,
id a4,
id a5)
{
……
}
- bool是返回值类型
- __cdecl 是一种函数调用约定(calling convention),指定由调用者负责清理堆栈
- - 表示是对象方法
- SpotifyAppDelegate是一个类,是该方法所属的类
- application:openURL:options:是方法签名
- application是方法名称
- openURL是参数2的形参名称
- options是参数3的形参名称
- ( _TtC24MusicApp_ContainerWiring18SpotifyAppDelegate *self, SEL a2, id a3, id a4, id a5)是方法的参数。每个参数都有一个类型和一个名称,用于在方法的实现中引用和操作这些参数。
- _TtC24MusicApp_ContainerWiring18SpotifyAppDelegate *self: 一个指向SpotifyAppDelegate对象的指针,表示方法的调用者。
- SEL a2: 一个选择器(Selector),表示方法的方法名。
- id a3, id a4, id a5: 这些是真正的参数,id类型,可以表示任意类型的对象。
该方法对应的方法签名是- (bool)application: (UIApplication *)application openURL: (NSURL *)url options: (NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
所以:
- id a3 对应的是参数1 application
- id a4对应的是参数2 url
- id a5对应的是参数3 options
OC中的block
https://juejin.cn/post/6844903525290360840
(1) 没有返回值、没有参数的block
void (^voidBlock)() = ^{};
voidBlock();
(2) 没有返回值、有一个参数的block
void (^parameterBlock)(NSInteger parameter) = ^(NSInteger parameter){
NSLog(@"=====parameterBlock");
};
parameterBlock(1);
(3)没有返回值、有两个参数的block
void (^parametersBlock)(int par1, int par2) = ^(int par1, int par2){
NSLog(@"=====parameterBlock");
};
parametersBlock(2,3);
等等
常见方法
stringFromObject:
作用是将一个对象转换为字符串形式