gpt4 book ai didi

ios - ObjC - 为什么允许实例访问 .m 文件中的类扩展属性?

转载 作者:行者123 更新时间:2023-11-29 11:30:25 29 4
gpt4 key购买 nike

众所周知,在 .h 文件中声明的 ObjC 属性是“外部可见”的接口(interface),而在 .m 文件(类扩展)中声明的属性只能在 .m 中访问,有点“私有(private)”或“隐藏” ”。但实际上可以编译如下代码。

A类.h

@interface ClassA : NSObject
+ (void)foo;
@end

A类.m

#import "ClassA.h"

@interface ClassA ()
@property (nonatomic) NSInteger aInt;
@end

@implementation ClassA
+ (void)foo {
ClassA *aObj = [ClassA new];
aObj.aInt = 2; //?
}
@end

@interface _ClassB : NSObject //Some private class defined in the same .m file...
@end
@implementation _ClassB

+ (void)bar {
ClassA* aObj = [ClassA new];
aObj.aInt = 2; //?
}

@end

事实是,不仅ClassA自己的方法中定义的ClassA *aObj可以访问类扩展属性aIntClassA *aObj定义在另一个_ClassB中,而在同一个ClassA.m文件中也可以访问aInt

据我了解,在类方法foo中定义的aObj与在另一个类中定义的任何ClassA *类型变量没有区别,并且单独的 .m 文件。但是后者决不会访问'aInt',比如说

ClassC.m

#import "ClassA.h"
...
- (void)fun {
ClassA *aObj = [ClassA new];
NSLog("%d", aObj.aInt); //Error! Property aInt not found on object of type 'ClassA*'
}

为什么会这样?这可以用 ObjC 运行时机制或其他东西来解释吗?

最佳答案

它与 Objective C 运行时无关。事实上,如果您使用键值编码,您可以从您想要的任何源文件访问任何类的任何属性和/或方法,它可以声明为私有(private)或不私有(private),或者在扩展中或直接声明。这就是某些人(禁止)使用 Apple 私有(private) API 的方式。

Objective C 和 C 一样,只需要知道你的类的声明。这是通过导入头文件来完成的。头文件说“看,有类似 ClassA 的东西,它有这些方法和那些属性”,然后你就可以使用它们了。

在 .m 文件中声明的任何内容对其他源文件都是不可见的,因为您通常不会导入 .m 文件(尽管从技术上讲,它是有效的)。尽管如此,该声明仍然存在 - 只是编译器在编译其他文件时不知道它。

您可以创建一个虚拟头文件:

// FakeClassAExtension.h
// ...
@interface ClassA (Fake)
@property (nonatomic) NSInteger aInt;
@end

然后在您的 ClassC 中使用它:

// ClassC.m
#import "ClassA.h"
#import "FakeClassAExtension.h"
//...
- (void)fun {
ClassA *aObj = [ClassA new];
NSLog("%d", aObj.aInt); //Fine
}

在编译 ClassC.m 时,编译器会知道 ClassA 中存在类似 aInt 的东西。链接器 - 作为最后一步 - 然后检查这是否真的是真的,例如如果一个(且只有一个)编译后的源文件包含 aInt 的定义。

试试这个:只需声明一个未在任何地方定义的属性:

// FakeClassAExtension2.h
// ...
@interface ClassA (Fake2)
@property (nonatomic) NSInteger oopsDoesItExist;
@end

然后使用它:

// ClassC.m
#import "ClassA.h"
#import "FakeClassAExtension2.h"
//...
- (void)fun {
ClassA *aObj = [ClassA new];
NSLog("%d", aObj.oopsDoesItExist); //Compiler is fine here
}

编译器将编译代码,但链接器随后会说定义 oopsDoesItExist

最后一点:您只能在 .m 文件中的类扩展(匿名类别)中定义 iVars 或综合属性。参见 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html

关于ios - ObjC - 为什么允许实例访问 .m 文件中的类扩展属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54105742/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com