标签: objective-c-runtime

为什么类NSObject上的某些方法(-retainWeakReference,-allowsWeakReference,+ load,+ initialize)不能在运行时添加到其他类?

它是在运行时简单的创建副本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 objective-c-runtime

14
推荐指数
1
解决办法
1390
查看次数

如何创建NSBlock对象?

我将在这个问题的前言中说明我要问的是教育和可能的调试目的.

如何在Objective C运行时内部创建块对象?

我看到所有类代表各种块类型的类的层次结构,下面的层次结构中最高的超类NSObjectNSBlock.倾销类的数据显示,它实现了+ alloc,+ allocWithZone:,+ copy+ copyWithZone:方法.其他块子类都没有实现这些类方法,这使我相信(可能是错误的NSBlock)负责块处理.

但是这些方法似乎在一个块的生命周期中的任何时候都不会被调用.我用自己的实现交换了实现并在每个实例中放置了一个断点,但是它们永远不会被调用.用NSObject实现做类似的练习给了我我想要的东西.

所以我假设块以不同的方式实现?任何人都可以了解这种实施方式的工作原理?即使我不能挂钩分配和复制块,我想了解内部实现.

objective-c objective-c-runtime objective-c-blocks

14
推荐指数
2
解决办法
3001
查看次数

获取任意类的类方法列表

如何获取特定类的方法列表?我已经尝试使用class_copyMethodList声明的函数<objc/runtime.h>,但这只是给我实例方法.我还找到了一个函数,它给了我一个类方法的方法,但前提是我有方法的选择器first(class_getClassMethod).

有任何想法吗?

谢谢,

戴夫

cocoa objective-c objective-c-runtime

13
推荐指数
2
解决办法
5548
查看次数

为什么我们不能将C字符串用作SEL?

所以,我一直在讨论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)

据我所知,选择器的内容是相同的,那么为什么第二个的崩溃会出现以下错误消息?

*** …

methods objective-c objective-c-runtime selector

13
推荐指数
1
解决办法
503
查看次数

Objective-C宏来检测变量是否是原始的

我正在寻找一个宏来检测变量是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 objective-c-runtime

13
推荐指数
1
解决办法
1237
查看次数

Objective-C对通用NSCoding实现的反思

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

12
推荐指数
2
解决办法
4226
查看次数

object_getInstanceVariable适用于float,int,bool,但不适用于double?

我必须在这里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通话结束后读取它时,该值不变.myIntValuegetinstancevar上面的函数之前设置为其他值应该返回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 return-value objective-c-runtime

12
推荐指数
1
解决办法
5538
查看次数

为什么protocol_*方法不适用于Linux上的Clang +现代GCC-Runtime?

我试图将我的一些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)

objective-c clang objective-c-runtime

12
推荐指数
1
解决办法
481
查看次数

如何计算ObjC方法类型编码中的数字?

是对我上一个问题的后续跟踪: ObjC方法类型编码字符串中的数字是什么?

说有一个编码:

v24@0:4:8@12B16@20
Run Code Online (Sandbox Code Playgroud)

这些数字是如何计算的?B是一个字符,所以它应该只占用1个字节(而不是4个字节).它与"对齐"有关吗?大小是void多少?

如下计算数字是否正确?询问sizeof每个项目并将结果四舍五入到4的倍数?第一个数字成为所有其他数字的总和?

objective-c objective-c-runtime

12
推荐指数
2
解决办法
1354
查看次数

Swift isa指针重映射或其他支持的方法调配

Swift类是否具有可以重新映射的isa指针?

我们已经看到Swift 使用比Objective-C 更静态的方法调度,它(除非来自Foundation/NSObject的类设备)在运行时基于重映射方法实现防止了调配风格.

我想知道我们将如何实现基于方法拦截的动态功能,如观察者模式,通知等?目前所有这些东西都是由Objective-C层提供的,可以很容易地集成到Swift中.但是,如果我们想在我们自己的框架(或应用程序)中提供这些类型的功能,是否有必要在Objective-C中实现它们?我认为有一种方法可以"原生"地完成它.

另一种对Objective-C来说很常见的混合是重新映射isa-pointer来动态生成一个子类.Swift是否支持这种调配?如果没有什么拦截任意的方法调用的支持呢?

编辑: 正如@jatoben指出的那样,从arm64开始重新映射必须通过调用object_setClass()而不是直接访问该值来完成.这仍然被称为'isa指针调配'

objective-c objective-c-runtime swift

12
推荐指数
1
解决办法
3068
查看次数