它是在运行时简单的创建副本MyNSObject中的类 NSObject的:
首先,创建一个新的类对.
Class MyNSObject = objc_allocateClassPair(nil, "MyNSObject", 0);
Run Code Online (Sandbox Code Playgroud)
第二步从NSObject读取方法,协议和ivars ,并将它们添加到新类中.
uint instanceMethodCount;
Method *instanceMethodArray = class_copyMethodList([NSObject class], &instanceMethodCount);
for (int i = 0; i < instanceMethodCount; i++) {
Method method = *(instanceMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
BOOL success = class_addMethod(MyNSObject, selector, implementation, types);
}
free(instanceMethodArray);
uint protocolCount;
Protocol **protocolArray = class_copyProtocolList([NSObject class], &protocolCount);
for (int i = 0; i < …Run Code Online (Sandbox Code Playgroud) 我将在这个问题的前言中说明我要问的是教育和可能的调试目的.
如何在Objective C运行时内部创建块对象?
我看到所有类代表各种块类型的类的层次结构,下面的层次结构中最高的超类NSObject是NSBlock.倾销类的数据显示,它实现了+ alloc,+ allocWithZone:,+ copy和+ copyWithZone:方法.其他块子类都没有实现这些类方法,这使我相信(可能是错误的NSBlock)负责块处理.
但是这些方法似乎在一个块的生命周期中的任何时候都不会被调用.我用自己的实现交换了实现并在每个实例中放置了一个断点,但是它们永远不会被调用.用NSObject实现做类似的练习给了我我想要的东西.
所以我假设块以不同的方式实现?任何人都可以了解这种实施方式的工作原理?即使我不能挂钩分配和复制块,我想了解内部实现.
如何获取特定类的类方法列表?我已经尝试使用class_copyMethodList声明的函数<objc/runtime.h>,但这只是给我实例方法.我还找到了一个函数,它给了我一个类方法的方法,但前提是我有方法的选择器first(class_getClassMethod).
有任何想法吗?
谢谢,
戴夫
所以,我一直在讨论objc-runtime(惊喜),我在这里找到了一个有趣的代码块:
const char *sel_getName(SEL sel) {
#if SUPPORT_IGNORED_SELECTOR_CONSTANT
if ((uintptr_t)sel == kIgnore) return "<ignored selector>";
#endif
return sel ? (const char *)sel : "<null selector>";
}
Run Code Online (Sandbox Code Playgroud)
所以,这告诉我的是SEL,在每种习惯中,a 都等同于C弦.执行包含SEL的前16个字节的十六进制转储,@selector(addObject:)提供以下内容:
61 64 64 4F 62 6A 65 63 74 3A 00 00 00 00 00 00
这等于C字符串addObject:.
话虽如此,当我使用C字符串作为选择器时,为什么这段代码会崩溃?
SEL normalSEL = @selector(addObject:);
SEL cStringSEL = (SEL) "addObject:";
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1", @"2", nil];
[arr performSelector:normalSEL withObject:@"3"];
[arr performSelector:cStringSEL withObject:@"4"];
NSLog(@"%@", arr);
Run Code Online (Sandbox Code Playgroud)
据我所知,选择器的内容是相同的,那么为什么第二个的崩溃会出现以下错误消息?
*** …
我正在寻找一个宏来检测变量是Objective-C中的对象还是原语.
在这种情况下,我知道参数必须是一个变量,永远不会是一个表达式.
这是我提出的最好的事情:
#define IS_OBJECT(x) ( @encode(__typeof__(x))[0] == '@' )
#define IS_PRIMITIVE(x) ( !IS_OBJECT(x) )
Run Code Online (Sandbox Code Playgroud)
用法:
NSString *testString = @"test";
NSString *nilString = nil;
NSInteger testInteger = 1;
STAssertTrue(IS_OBJECT(testString), @"IS_OBJECT(testString) must be YES");
STAssertTrue(IS_OBJECT(nilString), @"IS_OBJECT(nilString) must be YES");
STAssertFalse(IS_OBJECT(testInteger), @"IS_OBJECT(testInteger) must be NO");
Run Code Online (Sandbox Code Playgroud)
肯定有更好的办法.
更新
考虑到@ChrisDevereux评论,我更新了IS_OBJECT宏.
#define IS_OBJECT(x) ( strchr("@#", @encode(__typeof__(x))[0]) != NULL )
Run Code Online (Sandbox Code Playgroud)
它现在通过:
NSString *testString = @"test";
NSString *nilString = nil;
NSInteger testInteger = 1;
Class classTest = [NSString class];
STAssertTrue(IS_OBJECT(testString), @"IS_OBJECT(testString) must be YES");
STAssertTrue(IS_OBJECT(nilString), @"IS_OBJECT(nilString) must …Run Code Online (Sandbox Code Playgroud) Objective-C中是否存在任何反射方法,允许您通过检查对象的公共属性并生成encodeWithCoder:和initWithCoder的通用实现来编写通用NSCoding实现:.
我正在考虑像XStream for Java这样的东西,它允许使用反射对Java对象进行序列化和反序列化的通用方法.更好的方法可能是将属性标记为您想要序列化的东西或者是瞬态的(比如Java中的transient关键字).
我一直在阅读有关Cocoa的Archives and Serializations Programming Guide的文档.我知道您希望对对象的序列化进行一些控制,但它通常是一个对称的过程,并且必须反转为序列化编码的内容以反序列化它似乎很奇怪.我是DRY的信徒(不要重复自己).
iphone reflection serialization objective-c objective-c-runtime
我必须在这里object_getInstanceVariable工作,但它似乎只适用于花车,bools和int不是双打.我确实怀疑自己做错了什么,但我一直在这么做.
float myFloatValue;
float someFloat = 2.123f;
object_getInstanceVariable(self, "someFloat", (void*)&myFloatValue);
Run Code Online (Sandbox Code Playgroud)
有效,myFloatValue = 2.123
但是当我尝试
double myDoubleValue;
double someDouble = 2.123f;
object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
Run Code Online (Sandbox Code Playgroud)
我得到myDoubleValue = 0.如果我尝试myDoubleValue在功能之前设置,例如.double myDoubleValue = 1.2f,当我在object_getInstanceVariable通话结束后读取它时,该值不变.myIntValue在getinstancevar上面的函数之前设置为其他值应该返回2,即.它已被改变.
然后我试了
Ivar tmpIvar = object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
Run Code Online (Sandbox Code Playgroud)
如果我这样做,ivar_getName(tmpIvar)我会得到"someDouble",但myDoubuleValue = 0仍然!然后我尝试ivar_getTypeEncoding(tmpIvar),我应该得到"d".
总而言之,如果typeEncoding = float,它是有效的,如果它是一个double,结果没有设置,但它正确读取变量,返回值(Ivar)也是正确的.
我必须做一些我无法看到的基本错误,所以如果有人能指出它,我会很感激.
我试图将我的一些Objective-C项目从GCC切换到Linux上的Clang.我使用了GCC 4.6.2运行时,因为Clang编译器没有附带一个.编译和链接工作,但使用protocol_*方法时,它们不起作用.
以下示例适用于GCC,但与Clang不符合预期:
#include <objc/runtime.h>
#include <stdio.h>
@protocol MyProtocol
+ aClassMethod;
- anInstanceMethod;
@end
void doIt(Protocol *p, SEL sel)
{
printf("the protocol: %p\n", p);
if (!p) return;
printf("the protocol's name: %s\n", protocol_getName(p));
struct objc_method_description d = protocol_getMethodDescription(p, sel, YES, YES);
printf("required: YES instance: YES ? %p\n", d.name);
d = protocol_getMethodDescription(p, sel, YES, NO);
printf("required: YES instance: NO ? %p\n", d.name);
d = protocol_getMethodDescription(p, sel, NO, YES);
printf("required: NO instance: YES ? %p\n", d.name);
d = protocol_getMethodDescription(p, sel, NO, …Run Code Online (Sandbox Code Playgroud) 是对我上一个问题的后续跟踪: ObjC方法类型编码字符串中的数字是什么?
说有一个编码:
v24@0:4:8@12B16@20
Run Code Online (Sandbox Code Playgroud)
这些数字是如何计算的?B是一个字符,所以它应该只占用1个字节(而不是4个字节).它与"对齐"有关吗?大小是void多少?
如下计算数字是否正确?询问sizeof每个项目并将结果四舍五入到4的倍数?第一个数字成为所有其他数字的总和?
Swift类是否具有可以重新映射的isa指针?
我们已经看到Swift 使用比Objective-C 更静态的方法调度,它(除非来自Foundation/NSObject的类设备)在运行时基于重映射方法实现防止了调配风格.
我想知道我们将如何实现基于方法拦截的动态功能,如观察者模式,通知等?目前所有这些东西都是由Objective-C层提供的,可以很容易地集成到Swift中.但是,如果我们想在我们自己的框架(或应用程序)中提供这些类型的功能,是否有必要在Objective-C中实现它们?我认为有一种方法可以"原生"地完成它.
另一种对Objective-C来说很常见的混合是重新映射isa-pointer来动态生成一个子类.Swift是否支持这种调配?如果没有什么是拦截任意的方法调用的支持呢?
编辑: 正如@jatoben指出的那样,从arm64开始重新映射必须通过调用object_setClass()而不是直接访问该值来完成.这仍然被称为'isa指针调配'
objective-c ×10
clang ×1
cocoa ×1
iphone ×1
methods ×1
reflection ×1
return-value ×1
selector ×1
swift ×1