我正在考虑this page关于来自Objective C的C ++差异,并指出:
Objective C的动态特性允许在运行时扩展现有类。 Objective C允许您定义类别,相对于您已创建的对象的扩展集。例如,在将基于文本的应用程序转换为图形应用程序时,您的对象自己绘制的代码可以编译为类别,并仅在需要时在运行时加载。这样可以节省内存并允许您不加修改原始对象。
现在我熟悉类别并使用它们,但我看不出它们如何导致动态加载。如果你import
是一个类别文件,它是不是与它扩展的类一起编译的,每当你使用该类时占用内存,你是否使用了类别方法?
答案 0 :(得分:1)
您可以在运行时加载bundle / plugin / framework。这是引用引用的Objective-c的动态特性。它不是特定的类别。
但是,如果您加载的(已编译)代码在现有类中包含一个类别,则扩展将像它们一直存在一样工作。即编译时类不是“冻结”,加载包/插件/框架是在运行时向现有类添加新方法的一种方法。
与其他一些基于C语言的编译语言相比,这使得实现插件架构相对容易,或者仅在需要时加载代码以加快应用启动时间/保持内存占用率降低。
答案 1 :(得分:0)
如果链接包含类别的静态库,链接器会将所有类别代码复制到可执行文件中。如果您链接到共享库,共享库的整个代码段将映射到您的进程的地址空间,但它会被懒惰地分页,因此除非您全部使用它,否则您实际上可能无法读取磁盘上的所有类别代码。 / p>
但我认为这不是网页所说的。
首先,让我们谈谈你告诉链接器链接你的应用程序的库。
考虑NSString
。 NSString
类在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来加载插件,插件提供了一些子类的子类,或者符合我们专门为插件实现的协议。我们只需要获取该类的名称,然后创建它的实例并将其发送给我们在基类或协议中定义的消息。