2

我正在查看有关 C++ 与 Objective C 的差异的页面,它指出:

Objective C 的动态特性允许在运行时扩展现有的类。Objective C 允许您定义类别、相关的扩展集到您已经创建的对象。例如,在将基于文本的应用程序转换为图形应用程序时,您的对象需要绘制自己的代码可以编译为一个类别,并仅在需要时在运行时加载。这可以节省内存并允许您保持原始对象不变。

现在我熟悉类别并使用它们,但我不明白它们如何导致动态加载。如果您import是 Category 文件,它是否不会与它扩展的类一起编译,无论何时使用该类都会占用内存,无论您是否使用 Category 方法?

4

2 回答 2

1

您可以在运行时加载包/插件/框架。这是引用引用的 Objective-c 的动态特性。它不特定于类别。

但是,如果您加载的(已编译)代码在现有类中包含类别,则扩展将像它们一直存在一样工作。即一个类在编译时不是“冻结”的,加载一个包/插件/框架是在运行时向现有类添加新方法的一种方法。

与其他一些基于 C 的编译语言相比,这使得实现插件架构或仅在需要时加载代码以使应用程序启动时间更快/减少内存占用相对容易。

于 2012-11-15T08:40:12.773 回答
0

如果您与包含类别的静态库链接,则链接器会将所有类别代码复制到您的可执行文件中。如果您与共享库链接,则共享库的整个代码段将映射到您的进程的地址空间,但它是延迟分页的,因此您实际上可能不会从磁盘中读取所有类别代码,除非您全部使用它。

但我认为这并不是该页面真正在谈论的内容。

链接时库

首先,让我们谈谈您告诉链接器链接您的应用程序的库。

考虑NSString。该类NSString在 Foundation 框架中定义,该框架充满了通用类,这些类在具有 GUI 的程序和没有 GUI 的程序中很有用。因此NSString,Foundation 中定义的类不包含任何用于将字符串绘制到图形上下文中的代码,因为该代码(通常)在非 GUI 应用程序中是无用的。

AppKit 框架(在 OS X 上)管理一个 GUI。在 GUI 中能够将字符串绘制到图形上下文中很有用,因此 AppKit 包含一个类别,NSString用于添加绘制字符串的方法,例如drawAtPoint:withAttributes:. UIKit(在 iOS 上)做同样的事情(但方法有点不同)。

因此,如果您在 OS X 上编写程序并使用 Foundation 但不使用 AppKit,您的进程将不会加载 AppKitNSString类别,并且您不会为NSString.

对于像 AppKit 这样的共享库,在现代硬件上的价格是微不足道的。

现在,您可以使用自己的库做同样的事情,您可以将其设为静态。假设您创建了一个“TwitterModel”库来与 Twitter 交谈。它充满了模拟你在 Twitter 上找到的东西的类,比如帐户和推文。但是您不包含用于管理 GUI 以显示推文的代码。

相反,您创建了另一个库“TwitterGUI”,它(除了定义更多类)使用类别将方法添加到“TwitterModel”库中的模型类。

如果您编写一个链接到 TwitterGUI 和 TwitterModel 的程序,可执行文件将包含来自这两个库的所有 Objective-C 代码。但是,如果您编写一个仅命令行程序(无 GUI)并且仅将其与 TwitterModel 链接,则该程序将不包含任何与 GUI 相关的代码。哦,储蓄!

运行时库

现在让我们考虑您没有告诉链接器链接您的应用程序的共享库。

您可以在运行时使用 APIdlopen-[NSBundle load]. 如果库包含类别,这些类别将添加到您正在运行的程序中的类中。

因此,您可以通过尝试以编程方式加载库来使您的应用程序有选择地使用共享库(如果用户系统上存在共享库)。如果成功,您可以调用您知道库定义的任何类别方法。(当然,您可以使用库提供的类,如果有的话。)如果您无法加载库,请小心避免从库中调用任何这些类别方法。

但是,通常情况下,我们使用动态加载 API 来加载插件,并且插件提供了一些类,这些类是基类的子类,或者符合我们专门为要实现的插件定义的协议。我们只需要获取该类的名称,然后我们创建它的一个实例并将我们在基类或协议中定义的消息发送给它。

于 2012-11-15T08:57:18.077 回答