Jacky's blog
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)
  • iOS 学习开发指南
  • 调研

  • 其他

    • iOS术语
    • swift语法
    • oc语法
      • 基础
        • category
        • #pragma mark - xxx
        • +\- 符号
        • 关键字 NO/YES
        • 字符串
        • isKindOfClass
        • 带有 defaultValue 的方法
        • id 引用任何对象
        • NSCopying 协议
        • 字符串
        • macros 简化代码
        • @protocol 关键字
        • @protocol 与 @interface
        • define class
        • @property 定义属性
        • NSArray
        • NS_ENUM 宏定义
        • 基本数据类型
        • 复杂数据类型
        • SEL
        • ^ 符号
        • 返回闭包
        • UITableView
        • @selector 关键字
        • \[...\] 符号
        • _ 属性说明
    • 原理
    • 项目构建
    • iPhone技巧
    • ui
    • pod
    • xcode的使用
  • 《iOS》
  • 其他
Jacky
2023-10-08
目录

oc语法

# 基础

# category

Objective-C 中的分类(Category)是一种强大的特性, 它允许你为现有的类(包括标准类和你自己创建的类)添加新的方法, 而无需创建子类。分类提供了一种在不修改原始类的情况下扩展其功能的方式。你可以在分类中添加实例方法、类方法、甚至属性。Categories Add Methods to Existing Classes (opens new window)

下面是一个示例, 展示了如何创建一个分类:

// MyClass.h
@interface MyClass : NSObject
- (void)originalMethod;
@end

// MyClass.m
@implementation MyClass
- (void)originalMethod {
    NSLog(@"Original method");
}
@end
1
2
3
4
5
6
7
8
9
10
11

现在, 假设你想要为 MyClass 添加一个新的方法, 但你不想修改 MyClass 的源代码。你可以创建一个分类:


// MyClass+MyCategory.h
#import "MyClass.h"

@interface MyClass (MyCategory)
- (void)newMethod;
@end

// MyClass+MyCategory.m
@implementation MyClass (MyCategory)
- (void)newMethod {
    NSLog(@"New method");
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14

现在, MyClass 类有了一个新的方法 newMethod, 而不需要修改 MyClass 类的原始实现。你只需导入 MyClass+MyCategory.h 头文件, 就可以在你的代码中使用 newMethod

注意, 分类允许你扩展现有类的功能, 但不允许你添加新的实例变量。此外, 如果多个分类为同一个类添加同名的方法, 编译器可能无法确定使用哪个实现, 因此要谨慎处理。一般来说, 建议为分类的方法加上自定义前缀, 以避免冲突

# #pragma mark - xxx

#pragma 开头的代码是一条编译器指令, 是一个特定于程序或编译器的指令。它们不一定适用于其它编译器或其它环境。如果编译器不能识别该指令, 则会将其忽略。它们告诉 Xcode 编译器, 要在编辑器窗格顶部的方法和函数弹出菜单中将代码分隔开

# +\- 符号

- 符号用于实例方法, 而 + 符号用于类方法,类似于 java 中的 static 方法

# 关键字 NO/YES

在 Objective-C 中, NO 是一个关键字, 表示逻辑假(false)。它是布尔值 false 的等效表示。与之对应的关键字是 YES, 表示逻辑真(true)

# 字符串

@"%p preload model with idx %@ properties %@", self, @(self.context.model.pageIndex), property

在 Objective-C 字符串中, 使用@"..."表示字符串字面量。在这个字符串字面量中, %@ 是一个格式占位符, 通常用于插入对象的值

在你的代码片段中, @"%p preload model with idx %@ properties %@" 是一个包含了格式占位符的字符串。每个占位符都会在字符串中的相应位置插入一个值, 这些值是由占位符后面的变量提供的

  • %p 是一个占位符, 表示将一个指针地址插入到字符串中
  • %@ 也是一个占位符, 通常用于插入 Objective-C 对象的值

具体到你的代码片段, self 表示当前对象的指针, @(self.context.model.pageIndex) 用于将整数值转换为 Objective-C 对象, property 可能是另一个 Objective-C 对象。所以, %@ 占位符用于将这些值插入到字符串中, 以生成一个包含这些值的日志信息

例如, 如果 self 指向的对象的地址是 0x12345678, self.context.model.pageIndex 的值是 5, property 包含字符串"example", 那么这个字符串字面量就会被格式化为:

"0x12345678 preload model with idx 5 properties example"

这样的字符串可以用于日志记录或调试目的

# isKindOfClass

isKindOfClass 方法是 NSObject 的一个对象方法, 用于检查对象的类是否与指定类相同或是其子类。如果相同或是子类, 该方法返回 YES, 否则返回 NO

if ([model isKindOfClass:[XXX class]] == NO) {
    return;
}
1
2
3

冒号(:)后面的 [XXX class] 是一个消息发送的语法, 用于调用对象的方法

让我解释一下代码的意思:

  • [XXX class] 表示获取类 XXX 的实例。这是一个类方法, 它返回一个代表 XXX 类的 Class 对象
  • isKindOfClass: 是一个消息(方法)名称, 它接受一个 Class 对象作为参数, 并用于检查调用它的对象是否是该类或其子类的实例
  • [model isKindOfClass:[XXX class]] 这一部分将返回一个布尔值(YES 或 NO), 指示 model 是否是 XXX 类或其子类的实例
  • == NO 用于检查上面的条件是否为假。如果 model 不是 XXX 类或其子类的实例, 条件成立, 然后 return; 语句会导致函数的提前返回

# 带有 defaultValue 的方法

解析: - (NSString *)castStringForKey:(id<NSCopying>)key default:(NSString *)defaultValue;

  • 方法名 "castStringForKey:default:" 明确表明它的作用是从字典中获取指定键对应的字符串值, 并且提供了一个默认值, 以便在必要时返回。这种命名方式能够让开发者清晰地了解方法的功能, 并在需要时使用默认值, 而不会引发异常或错误
  • 参数: 接受两参数, 一个是 key, 它应该是符合 NSCopying 协议的对象, 通常用作字典的键;另一个是 defaultValue, 它是一个 NSString 类型的默认值, 用于在无法找到指定键对应的值时返回
  • 在 OC 中, 冒号后面的才是参数

# id 引用任何对象

对象的指针为什么要用 id 来表示, 比如 A 类的指针直接使用 A*不就可以了吗

你的疑问是很合理的。在 Objective-C 中, 确实可以使用类指针来表示对象, 比如 A* 表示类 A 的对象。实际上, A* 是一种具体的数据类型, 用于指向 A 类的实例

而 id 是一种更加通用和灵活的数据类型, 它可以指向任何 Objective-C 对象, 不仅仅是 A 类的对象。这使得 id 更具通用性, 允许在不确定对象类型的情况下引用对象

为什么要使用 id 呢?

这主要是因为 Objective-C 是一种动态类型语言, 它允许在运行时动态确定对象的类型。使用 id 可以更容易地实现这种动态性, 因为它不限制你在编译时指定对象的具体类型。这在 Objective-C 的动态特性中是非常有用的, 特别是在处理集合类、代理、反射等情况下

所以, 虽然可以使用类指针来表示对象, 但 id 更加通用, 可以在更多的情况下使用, 特别是在 Objective-C 动态性和灵活性的背景下

# NSCopying 协议

NSCopying 是 Foundation 框架中的一个协议, 通常用于 Objective-C 中的对象复制操作。对象遵循 NSCopying 协议的话, 就需要提供一种复制(或克隆)对象的方式, 以便创建一个新的对象, 该对象与原始对象具有相同的内容。这个协议定义了一个方法:

- (id)copyWithZone:(NSZone *)zone;
1

这个方法返回一个新对象的副本, 通常由类的实例来实现。copyWithZone 方法的实现需要在新对象中复制原始对象的属性和数据, 以便新对象也能正确工作。NSZone 参数通常可以被忽略, 除非你有特定的需求

遵循 NSCopying 协议的对象通常是不可变的, 因为它们的内容在复制后不能被修改。这在 Objective-C 中非常有用, 因为你可以创建一个原始对象的不可变副本, 以确保数据的安全性和不可修改性

在实际开发中, 如果你定义了一个自定义的 Objective-C 类, 而你希望该类的实例能够进行复制操作, 你可以让该类遵循 NSCopying 协议, 并实现 copyWithZone 方法来定义如何复制对象的行为。这对于创建对象的副本, 而不改变原始对象的状态非常有用

# 字符串

  • NSString: The basic NSString class is immutable
  • NSMutableString: The NSMutableString class is the mutable subclass of NSString

# macros 简化代码

示例一

#define SVC_VC_SERVICE(PROPERTY, SERVICE)\
- (id<SERVICE>)PROPERTY\
{ return [self.componentManager getService:@protocol(SERVICE)]; }
1
2
3

这段代码是 Objective-C 中的宏定义(#define), 用于定义一个属性宏, 以便通过属性名访问组件或服务。该宏定义会生成一个类的方法, 使开发者能够通过该属性名称直接获取相应的服务对象

这是一个通用的宏定义, 它包含两个参数:

PROPERTY: 这个参数表示属性的名称, 通常是一个属性的名称字符串 SERVICE: 这个参数通常是一个协议名, 它表示你想要获取的服务的类型 这个宏定义生成的方法的功能是, 根据给定的服务协议(SERVICE)从 componentManager 中获取相应的服务对象。componentManager 是一个管理组件或服务的对象, 可能是一个单例对象, 它包含了各种服务的实例。这个宏允许你通过属性名直接访问这些服务

实际使用时, 你可以在类的接口部分使用这个宏, 如下所示:

SVC_VC_SERVICE(myService, MyServiceProtocol)
1

这会生成一个名为 myService 的属性, 该属性的类型是 id<MyServiceProtocol>, 也就是符合 MyServiceProtocol 协议的对象。在类的实现中, 你就可以使用这个属性来获取相应的服务

这种宏定义的好处是, 它提供了一种更简洁的方式来获取服务, 而不必在每个需要使用服务的地方都编写繁琐的代码。宏定义可以减少代码的冗余, 提高代码的可维护性

示例二

#define LMJWeak(type)  __weak typeof(type) weak##type = type
1
  • __weak 是 Objective-C 中的关键字, 用于声明一个弱引用。它创建一个指向对象的弱引用, 不会增加对象的引用计数, 从而避免了循环引用的问题

  • weak##type 中的 ## 是一个连接符, 用于将 weak 和 type 连接在一起, 从而创建一个带有 type 名称前缀的弱引用变量。这样, weak##type 就成为了一个以 weak 为前缀、后面跟着 type 名称的弱引用变量, 例如 weakself 或 weakobject

所以, 这个宏定义的作用是为了创建一个带有指定前缀的弱引用变量, 可以根据 type 参数的不同, 生成不同的变量名。这有助于在 block 内部安全地引用对象, 避免循环引用

# @protocol 关键字

更多内容请点击: 协议 (opens new window)

@protocol 是 Objective-C 中的一个关键字, 用于定义协议(Protocol)。Protocols can include declarations for both instance methods and class methods, as well as properties.

基础语法如下:

@protocol ProtocolName
// list of methods and properties
@end
1
2
3

Objective-C 中的协议类似于其他编程语言中的接口(Interface)或抽象类(Abstract Class), 它们用于描述类应该具有的特定行为, 但不提供实际的代码实现。协议在 Objective-C 中具有以下 特点:

  • **声明方法和属性: **: 协议可以包含一组方法和属性的声明, 但不提供实际的方法体或属性实现。这些声明在协议中只是描述, 没有具体代码

  • **可选或强制实现: **: 协议中的方法可以被标记为可选或强制实现。强制实现的方法必须在遵循协议的类中提供具体的实现, 而可选方法可以选择性地实现。这为类提供了一定的灵活性

  • **多继承: **: Objective-C 支持多重继承, 一个类可以遵循多个不同的协议。这允许类获得来自多个协议的行为

  • **委托模式: **: 协议常用于实现委托模式, 其中一个对象委托另一个对象执行某些任务。例如, UIKit 中的代理(Delegate)通常是协议的实现

  • **面向协议编程: **: Objective-C 通过协议支持面向协议编程, 这种编程风格侧重于对象之间的通信和合作, 而不仅仅是类的继承关系

定义一个协议示例:

@protocol MyProtocol <NSObject>

@required
- (void)requiredMethod;

@optional
- (void)optionalMethod;

@end
1
2
3
4
5
6
7
8
9

在上面的示例中, MyProtocol 定义了两个方法: requiredMethod 是一个强制实现的方法, 而 optionalMethod 是一个可选方法。类可以遵循该协议并提供这些方法的具体实现

  • <NSObject>: 这是一个协议的继承。通过继承自 NSObject 协议, MyProtocol 协议将继承 NSObject 协议中定义的方法和属性。这包括了 Objective-C 中的基本对象操作, 例如内存管理和方法调用

遵循协议的示例:

@interface MyClass : NSObject <MyProtocol>
@end
1
2

上述代码表示 MyClass 类遵循了 MyProtocol 协议, 因此它必须提供 requiredMethod 方法的具体实现, 而 optionalMethod 是可选的

协议在 Objective-C 中是一种非常强大和灵活的特性, 它使得不同类可以共享一组通用的行为规范, 从而提高了代码的重用性和可维护性

# @protocol 与 @interface

  • Objective-C 中的协议 (@protocol), 相当于 C#, Java 等语言中的接口 (Interface)。协议本身不实现任何方法, 只是声明方法, 使用协议的类必须实现协议方法

  • Objective-C 中的接口 (@interface), 相当于 C#, Java 等语言中的类(Class), 是类的一个声明, 不同与 C#, Java 等语言的接口

  • Objective-C 中的类必须要有接口, 但不一定都要有协议。使用协议的类, 必须实现协议中的方法

  • Objective-C 中的父类中如果已经使用了协议 (@protocol), 并实现了协议中的方法, 那么其子类就要添加相同的协议 (@protocol), 也不需要再重复实现协议中的方法, 除非必要。这和 C#, Java, 等语言中的接口 (Interface) 使用方法一致

# define class

  • - (void)someMethodWithFirstValue:(SomeType)value1 secondValue:(AnotherType)value2;: 类的定义

初始化方法

- (instancetype)init {
    self = [super init]; // Call the designated initializer of the superclass.

    if (self) {
        // Initialize your object's properties and perform setup here.
        self.property1 = defaultValue1;
        self.property2 = defaultValue2;
        // ...
    }

    return self;
}
1
2
3
4
5
6
7
8
9
10
11
12

# @property 定义属性 (opens new window)

语法

@property (assign, nonatomic) Class destVc;
1

修饰

  • nonatomic: it’s faster to access a nonatomic property than an atomic one
  • assign: 通常用于修饰基本数据类型的属性, 例如整数 (int)、浮点数 (float)、指针等。它告诉编译器在设置属性的新值时不要自动处理内存管理, 仅仅是简单地赋值
    • 【注】在使用 assign 修饰符时, 你需要特别小心, 确保不会在属性引用的对象被释放后再次访问该属性, 因为它不会自动设置属性为 nil。这可能导致悬垂指针或访问已释放内存的问题。因此, assign 修饰符通常在非对象类型的属性上使用, 而对象属性通常使用更安全的修饰符, 以自动处理内存管理
  • readonly: don’t want to allow a property to be changed via a setter method
  • readwrite: default
  • getter=isFinished: use a different name for an accessor method

属性的set/get方法

- (UITableView *)tableView
{
    if(_tableView == nil)
    {
        UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:self.tableViewStyle];
        [self.view addSubview:tableView];
        tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _tableView = tableView;
    }
    return _tableView;
}
1
2
3
4
5
6
7
8
9
10
11

这是一个属性的自定义 getter 方法。在 Objective-C 中, 当你使用 @property 声明一个属性时, 编译器会自动为你生成 getter 和 setter 方法, 但你也可以自定义它们, 以实现特定的行为

在你提供的代码中, 你自定义了 tableView 属性的 getter 方法。这个 getter 方法首先检查 _tableView 是否为 nil, 如果是 nil, 则创建一个新的 UITableView 对象, 将其添加到视图中, 设置自动调整大小的属性, 然后将它赋值给 _tableView。最后, 它返回 _tableView

这种方式常用于懒加载(lazy loading), 即只有在首次访问属性时才会创建和初始化对象, 以节省资源和提高性能。如果 _tableView 已经被初始化过, 那么它将直接返回已存在的对象, 避免重复创建

所以, 这是属性的 getter 方法, 用于获取 tableView 属性的值


# NSArray

解释 NSMutableArray *mulArray = @[].mutableCopy;

这行代码创建了一个可变数组对象 mulArray, 并使用数组字面量语法(@[])初始化它, 然后通过 mutableCopy 方法创建了 mulArray 的可变副本。让我一步一步解释这行代码:

  • @[]: 这是 Objective-C 中的数组字面量语法。它创建一个空的不可变数组

  • .mutableCopy: 这是一个方法调用, 应用于不可变数组上, 用于创建一个可变数组的副本。在这里, @[] 创建的不可变数组被复制为一个可变数组

所以, NSMutableArray *mulArray 保存了一个空的可变数组, 你可以随后向它添加元素, 使其动态地扩展和管理数据。这种方式通常用于初始化一个可变容器, 以后可以根据需要向其中添加或删除元素

# NS_ENUM 宏定义

NS_ENUM 不是一个关键字, 它是一个宏, 用于定义带有命名常数的枚举。这个宏的目的是帮助开发人员更容易地创建具有特定类型的枚举

以下是 NS_ENUM 的一般语法:

typedef NS_ENUM(枚举的底层类型, 枚举名) {
    枚举成员1,
    枚举成员2,
    // ...
};
1
2
3
4
5

举例说明

typedef NS_ENUM(NSUInteger, VideoComponentSceneType) {
    VideoComponentSceneOfRecommend = 1,
    VideoComponentSceneLandScape = 1 << 3, // 横竖屏
    VideoComponentSceneImageCollection = 1 << 4 // 图集
};
1
2
3
4
5
  • NSUInteger: 底层类型是

# 基本数据类型

Objective-C 是一种面向对象的编程语言, 它建立在 C 语言的基础上, 并扩展了 C 以支持面向对象编程。在 Objective-C 中, 有一些基本数据类型, 包括:

  • NSInteger 和 NSUInteger:

    • NSInteger 表示有符号整数, 通常用于存储整数值, 包括正数和负数
    • NSUInteger 表示无符号整数, 通常用于存储正数值。这两种类型的大小(位数)取决于底层操作系统的架构, 可以是 32 位或 64 位
  • BOOL:

    • BOOL 是布尔数据类型, 它只有两个值: YES 和 NO, 分别表示真和假。在 C 语言中, 这相当于 1 和 0
  • CGFloat 和 double:

    • CGFloat 表示浮点数, 通常用于存储小数值, 例如浮点数或双精度浮点数
    • double 是 C 语言中的浮点数据类型, 也用于存储小数值, 但具有更高的精度
  • char 和 NSString:

    • char 用于表示字符, 通常用于处理字符和字符串
    • NSString 是 Objective-C 中的字符串类型, 用于存储和操作文本数据
  • id:

    • id 是一个泛型对象指针, 可以引用任何 Objective-C 对象。这使得 Objective-C 具有动态类型的特性

这些基本数据类型都是 Objective-C 语言的一部分, 你可以使用它们来声明和操作不同类型的数据。另外, Objective-C 还提供了许多复杂的数据类型, 如数组、字典、集合等, 用于处理更复杂的数据结构

# 复杂数据类型

在 Objective-C 中, 你可以使用复杂的数据类型来表示更复杂的数据结构, 这些数据类型通常是基于 Objective-C 对象的。以下是一些常见的复杂数据类型:

  • NSArray: NSArray 是一个有序的集合, 可以包含多个对象, 对象类型可以不同。它是不可变的, 一旦初始化, 其内容不可更改。对应的可变版本是 NSMutableArray, 可以动态添加、删除、替换其中的元素

  • NSDictionary: NSDictionary 是一个键-值对的集合, 可以将键映射到相应的值。它也是不可变的, 对应的可变版本是 NSMutableDictionary

  • NSSet: NSSet 是一个无序的集合, 用于存储一组唯一的对象。它是不可变的, 对应的可变版本是 NSMutableSet

  • NSData: NSData 表示原始的二进制数据, 通常用于文件操作、网络传输等。有可变版本 NSMutableData, 允许修改数据

  • NSString: NSString 表示字符串数据。Objective-C 内置了对字符串的支持, 包括字符串的创建、连接、截取、查找等一系列操作

  • NSArray、NSDictionary、NSSet: 是集合类, 它们可以嵌套使用, 从而创建更复杂的数据结构。例如, 你可以创建一个包含字典的数组, 或者字典中包含其他数组, 以满足你的数据组织需求

  • 自定义对象: 你还可以定义自己的复杂数据类型, 通过创建 Objective-C 类, 这些类可以包含属性、方法、实例变量等。这些自定义类可以用来表示更复杂的数据结构, 比如用户、产品、订单等

  • 枚举类型: Objective-C 也支持枚举, 你可以用它来定义一组离散的值, 用于表示有限的选项, 例如颜色、状态等

  • **结构体: 虽然 Objective-C 主要是基于面向对象的编程, 但它也支持 C 语言的结构体, 你可以使用结构体来组织一组相关的数据

总之, Objective-C 提供了多种数据类型和数据结构, 允许你灵活地表示和操作各种复杂数据。你可以根据你的应用程序需求选择合适的数据类型

# SEL

更多查看 (opens new window)

我们要首先明白 SEL, SEL 并不是一种对象类型, 我们通过 xCode 的字体颜色就可以判断出来, 它是一个关键字, 就像 int, long 一样, 它声明了一种类型: 类方法指针。其实就可以理解为一个函数指针

# ^ 符号

return 后面的^符号

- (LMJStaticTableViewController *(^)(LMJWordItem *))addItem {

    LMJWeak(self);
    if (!self.sections.firstObject) {
        [self.sections addObject:[LMJItemSection sectionWithItems:@[] andHeaderTitle:nil footerTitle:nil]];
    }
    return  ^LMJStaticTableViewController *(LMJWordItem *item) {
        [weakself.sections.firstObject.items addObject:item];
        return weakself;
    };
}
1
2
3
4
5
6
7
8
9
10
11

在 Objective-C 中, ^ 符号表示一个 block 对象的开始, 也称为 block 语法。在你的代码中, return 后面的 ^ 符号用于定义一个 block。这个 block 接受一个 LMJWordItem 类型的参数 item, 并返回一个 LMJStaticTableViewController 对象

这种语法允许你创建一个能够在后续代码中执行的闭包, 这个闭包可以包含你定义的逻辑。在这个特定的情况下, 这个闭包用于向 LMJStaticTableViewController 的 sections 中添加 LMJWordItem 对象

这是一种非常强大的模式, 通常用于链式调用 API, 其中你可以依次添加多个元素或配置参数, 并且在代码中保持良好的可读性和流畅性

# 返回闭包

- (LMJStaticTableViewController *(^)(LMJWordItem *))addItem {}

这是一个 Objective-C 方法的声明, 它具有以下特点:

  • 返回类型: LMJStaticTableViewController _(^)(LMJWordItem _) 表示这个方法返回一个 block 对象, 该 block 接受一个 LMJWordItem 类型的参数, 并返回一个 LMJStaticTableViewController 对象

  • 方法名称: addItem 是这个方法的名称

  • 方法参数: 这个方法没有显式的参数, 但它返回的 block 对象具有一个参数, 即 LMJWordItem 类型的对象

  • 返回值: 返回一个 block 对象, 该 block 接受 LMJWordItem 类型的参数, 然后返回 LMJStaticTableViewController 对象

# UITableView

  • NSIndexPath: <>

# @selector 关键字

在 Objective-C 中, @selector 是一个关键字, 用于创建一个选择器对象, 它通常用于表示方法名称。在上述代码中, @selector(runExitAction) 创建了一个选择器, 表示名为 runExitAction 的方法

选择器对象通常用于以下几种情况:

  1. 作为方法的参数: 你可以将选择器作为参数传递给某个方法, 以便在运行时动态调用特定的方法

  2. 作为键: 选择器可以作为 NSDictionary 或其他数据结构中的键, 用于关联方法和其他数据

  3. 用于比较: 你可以使用选择器来比较两个方法是否相同

代码示例

-(void)ExitThread
{
    _myThread = nil;
    if (!self.myThread) {
        self.myThread=[[NSThread alloc]initWithTarget:self selector:@selector(runExitAction) object:nil];
        self.myThread.name=@"thread-exit";
    }
    [self.myThread start];
}
1
2
3
4
5
6
7
8
9

在上面的代码中, @selector(runExitAction) 创建了一个选择器, 用于表示 runExitAction 方法。一旦你有了这个选择器, 你可以使用它来执行或比较方法。在创建线程时, 你指定了这个选择器作为线程的执行点, 这意味着线程将在后台执行 runExitAction 方法中的代码

# [...] 符号

item27.destVc = [LMJNavBarFadeViewController class];

在 Objective-C 中, 中括号 [...] 用于消息传递的语法。Objective-C 是一门基于消息传递的编程语言, 与其他语言的方法调用语法略有不同。下面是对你提供的代码的解释:

item27.destVc = [LMJNavBarFadeViewController class];
1

这行代码的含义是设置 item27 对象的 destVc 属性为 LMJNavBarFadeViewController 类。在这里, 中括号用于向 class 方法发送消息, 获取 LMJNavBarFadeViewController 类的对象。这通常用于获取类的信息或执行类方法

总结起来, 中括号 [...] 在 Objective-C 中用于向对象发送消息, 包括方法调用、属性设置和获取等操作

# _ 属性说明

@interface LMJCountDownCell : UITableViewCell

/** <#digest#> */
@property (nonatomic, strong) LMJCountDownModel *countDownModel;

@end
1
2
3
4
5
6

在 Objective-C 中, 通常使用下划线 _ 作为实例变量的前缀, 而不是直接访问属性。这是一种编码风格的约定, 有助于区分属性和实例变量, 以及避免潜在的命名冲突

在你的代码中, @property 声明了一个属性 countDownModel, 但这个属性在底层是由编译器自动生成的实例变量, 实例变量的名称是在属性名称前加下划线 _, 即 _countDownModel。这个实例变量用于在类内部存储属性的值

所以, 当你在类的方法中使用 _countDownModel 进行赋值或访问时, 你实际上在直接访问实例变量, 而不是通过属性的 getter 和 setter 方法。这种做法有助于避免属性访问器方法的递归调用和潜在的命名冲突

通常, 属性的 getter 方法会自动访问相应的实例变量, 所以在类的内部, 你可以直接访问实例变量来避免额外的性能开销。但在类的外部, 应该使用属性来访问和修改属性的值, 以确保属性的封装性和数据完整性。这也是为什么通常在属性的 getter 方法中使用 self.propertyName 而在类内部使用 self->_propertyName 或 _propertyName 的原因

上次更新: 2024/12/01, 17:07:39
swift语法
原理

← swift语法 原理→

最近更新
01
npx 使用指南
10-12
02
cursor
09-28
03
inspect
07-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式