类别提供动态加载?

时间:2012-11-15 07:54:55

标签: objective-c

我正在考虑this page关于来自Objective C的C ++差异,并指出:

  

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

现在我熟悉类别并使用它们,但我看不出它们如何导致动态加载。如果你import是一个类别文件,它是不是与它扩展的类一起编译的,每当你使用该类时占用内存,你是否使用了类别方法?

2 个答案:

答案 0 :(得分:1)

您可以在运行时加载bundle / plugin / framework。这是引用引用的Objective-c的动态特性。它不是特定的类别。

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

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

答案 1 :(得分:0)

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

但我认为这不是网页所说的。

链接时库

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

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

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

因此,如果您在OS X上编写程序并使用Foundation但不使用AppKit,则您的进程将不会加载AppKit NSString类别,并且您不会为所有这些图形付出代价NSString上的方法。

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

现在,您可以使用自己的库执行相同的操作,您可以将其设置为静态库。假设您创建了一个“TwitterModel”库,用于与Twitter交谈。它充满了对您在Twitter上发现的内容进行建模的类,如帐户和推文。但是,您不包含用于管理GUI以显示推文的代码。

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

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

运行时库

现在让我们考虑一下您没有告诉链接器将您的应用链接到的共享库。

您可以使用dlopen-[NSBundle load]等API在运行时动态地将新代码加载到流程中。如果库包含类别,那么这些类别将添加到正在运行的程序中的类中。

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

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