我理解一个类实际上是一个对象/struct (objc_class*) 的类型定义。
每个类都有一个“支持”元类,它又有一个指向 NSObject 元类的 isa 指针。
NSObject基本上有一个指向自身的 isa 指针。
我们可以通过这一行获取元类:
objc_getMetaClass("<CLASS_NAME>");
我希望到目前为止我对元类的理解没有偏离(如果是,请纠正我)。
我的问题是:
1.)
When would we need to deal with meta class? Could you please cite an example / a scenario in code when we might need to?
2.)
背景:
我在自由思考第三方库及其结构。
通常他们为您提供一个类方法并返回给您一个类,所有其他方法都是私有(private)的/“隐藏的”。大多数时候,虽然它们可以被子类化,但由于我们不知道 init 方法,因此子类化是没有用的。
突然间,我开始考虑Objective-C 类别,从而让我想到Objective-C 元类。
这引出了我的问题 #2:
Is it possible to break this structure by making use of Objective-C Category and / or with the use of meta class (by grabbing a hold of it and insert a class method straight there in the meta class)? Or even look up the name of their instance methods that are private?
我的目的不是要“破坏”任何东西,我只是很好奇这些第三方库的结构是如何“牢不可破”的,以及它们的结构是否不能通过使用类别 和 元类。
@Leo Natan:
1.)
什么是method_*()?
2.)
为了对 Objective-C 运行时的热爱:
你能举一个例子实现吗——调配一个实例方法,比方说,
(我不确定这个方法是否是一个很好的例子,因为我们可以首先覆盖它)
NSArray 的 -count 实例方法(让它总是返回计数 100,例如)
3.)
那么理论上所有类(包括所有第三方库)都可以被break(破坏)?换句话说,没有办法创建“仅调用此类方法或您不能使用我”的 API/库?
非常感谢。
最佳答案
当希望查看、添加或修改类方法和类级信息时,元类很有用。
例如,
IMP myIMP = imp_implementationWithBlock(^(id _self, NSString *string) {
NSLog(@"Hello %@", string);
});
Class cls = objc_getMetaClass("NSString");
class_addMethod(cls, @selector(test:), myIMP, "v@:@");
[NSString test:@"lala"];
要获取实例方法,您可以在对象上的 class 方法返回的类上使用 class_copyMethodList() 或 NSClassFromString()。您将获得该类(但不是其父类(super class)!)定义的所有实例方法的数组。然后,您可以使用各种 method_*() 方法来检索信息,甚至可能修改这些方法(如实现调配)。
您可以在元类上调用 class_copyMethodList() 以获取定义的所有类方法。
要解决您的“狮子座”问题,
1.
请阅读Objective C Runtime Reference .您可以找到处理 Method 结构的 method_ 函数部分。
2。 参见 tutorial关于实现调配。
3。 使用 Objective C,一切都可用于运行时。不用说,能力越大,责任越大。 Objective C 运行时非常强大。这些 swizzles 非常危险,通常不推荐使用。
关于iOS/Objective-C 元类和类别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20844583/
让我们计算MRI范围内的类别:defcount_classesObjectSpace.count_objects[:T_CLASS]endk=count_classes用类方法定义类:classAdefself.foonilendend然后运行:putscount_classes-k#=>3请解释一下,为什么是三个? 最佳答案 查看MRI代码,每次你创建一个Class时,在Ruby中它是Class类型的对象,ruby会自动为这个新类创建“元类”类,这是另一个单例类型的Class对象。C函数调用(class.c)是:rb_define
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#
我正在为ruby开发一个C扩展,但我需要包含来自IOBluetooth框架的header,特别是:#import#import一切都编译正常,但在运行时,扩展错误:path/to/file.rb:1:in`require_relative':dlopen(/path/to/extension.bundle,9):Symbolnotfound:_OBJC_CLASS_$_IOBluetoothDeviceInquiry(LoadError)我相当确定这与未包含在链接过程中的框架有关,但我不确定原因。任何帮助将不胜感激extconf.rb:#Loadsmkmfwhichisusedto
当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab