标签: objective-c-runtime

使用Objection时,自定义协议的实现与无法识别的选择器崩溃

我正在定义一个自定义协议:

@protocol NGSAuthProvider <NSObject>
- (BOOL)isReady;
- (BOOL)isSessionValid;
- (void)login;
- (void)logout;
- (NSString *)accessToken;
- (BOOL)handleOpenURL:(NSURL *)url;
@end
Run Code Online (Sandbox Code Playgroud)

我想拥有不同的提供商.所以一个是Facebook提供商:

@interface NGSFacebookAuthProvider : NSObject <NGSAuthProvider>
@end

@interface NGSFacebookAuthProvider () <FBSessionDelegate>
@property BOOL ready;
@property(nonatomic, retain) Facebook *facebook;
@property(nonatomic, retain) NSArray *permissions;
@end

@implementation NGSFacebookAuthProvider
//Implementation of fbLogin, fbLogout and the methods in NGSAuthProvider that forward calls to self.facebook
- (NSString *)accessToken
{
  return [self.facebook accessToken];
}

@end
Run Code Online (Sandbox Code Playgroud)

我设置了Objection从我的类绑定到协议.

@interface NGSObjectionModule : ObjectionModule
@end

@implementation NGSObjectionModule

- (void)configure 
{ …
Run Code Online (Sandbox Code Playgroud)

objective-c objective-c-runtime

5
推荐指数
1
解决办法
800
查看次数

我如何获得ivar的Objective-C类?

NSManagedObject在单元测试中创建了一堆简单的s.它们只有一个name类型的属性NSString *.我总是给我NSManagedObject相同entityNameClass名字.

我想避免编写以下代码30次来设置单元测试:

@interface FooTest : GHTestCase {
Foo *foo;
}
@end
@implementation FooTest

- (void) setUp {
  [super setUp];

  foo = [NSEntityDescription insertNewObjectForEntityForName:@"Foo"
                                      inManagedObjectContext:managedObjectContext];
  foo.name = @"foo";
}
@end
Run Code Online (Sandbox Code Playgroud)

既然foo是一个ivar,我认为我应该能够写一个宏来获取foo(Foo)的类型,并用来创建我的Foo:

#define InsertManagedObjectByVariable(variable) \
do { \
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])]; \
variable.name = (NSString *) CFSTR(#variable);
} while(0)
Run Code Online (Sandbox Code Playgroud)

但是,这会在clang中导致以下警告:

variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])];
                                                                               ^
                                                             Expected expression
Run Code Online (Sandbox Code Playgroud)

我还以为我可以尝试确定使用Objective-C的运行时类型 …

c objective-c objective-c-runtime

5
推荐指数
2
解决办法
1825
查看次数

实例变量和方法如何存储在Objective-C 2.0对象中?

在Objective-C的遗留版本中,objc_class结构实现如下:

struct objc_class {
    Class isa;
    Class super_class;
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list **methodLists;
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
};
Run Code Online (Sandbox Code Playgroud)

因此,表示对象的结构存储指向对象类的指针,指向对象超类的指针,对象的类名,对象的版本,信息和实例大小,对象的实例变量列表,对象的方法列表,对象的缓存和对象的协议列表.在表示对象的结构中存在这些字段是非常容易理解的,因为它们中的每一个都存储有关该对象的信息.

但是,相同的struct objc_class的Objective-C 2.0实现是这样的:

struct objc_class {
    Class isa;
};
Run Code Online (Sandbox Code Playgroud)

因此,在这个版本的objc_class中,struct中只有一个字段:指向对象类结构的指针.

那么,我的问题是,对象的其他信息是如何存储在Objective-C 2.0中的,因为结构中只有一个表示对象的字段?

objective-c objective-c-runtime

5
推荐指数
1
解决办法
347
查看次数

forwardInvocation如何调用?

仅查看Objective-C运行时库,当消息发送到不响应它的对象时,运行时系统为接收者提供了另一个处理消息的机会.因此,接收者的forward::方法(如果实现的话)被调用.但是,看看NSObject.mm,NSObject似乎没有实现forward::.

那么,如何NSObjectforwardInvocation:方法被调用,因为需要转发时运行系统调用的唯一的事情是forward::?Foundation是否使用objc_setForwardHandler(runtime.h)设置一个新的处理程序,forwardInvocation:只要发送到NSObject对象的消息需要转发,它就会调用?

forwarding objective-c objective-c-runtime nsobject nsinvocation

5
推荐指数
1
解决办法
3638
查看次数

dispatch_once是否在+ [NSObject initialize]内部过度杀伤?

如果我在里面创建一个单例+[NSObject initialize],我是否需要将我的代码放在一个dispatch_once块中?

static NSObject * Bar;
@implementation Foo
+ (void)initialize {
  if (self == [Foo class]) {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      Bar = [NSObject new];
    });
  }
}
@end
Run Code Online (Sandbox Code Playgroud)

编辑

我很关心这个,因为我想确保所有线程都会看到我调用Bar之后设置的+[Foo initialize].文档说+[NSObject initialize]是线程安全的,但这是否意味着它是内存安全的?

concurrency objective-c objective-c-runtime grand-central-dispatch ios

5
推荐指数
2
解决办法
1162
查看次数

ios 6和7不会返回相同的结果

似乎我们使用的应用程序getPropertyType(..)在ios7下失败了.无论出于何种原因,getPropertyType(..)例如NSString属性NSString$'\x19\x03\x86\x13作为类型返回,而不仅仅是NSString,而不是返回NSNumber NSNumber\xf0\x90\xae\x04\xff\xff\xff\xff.当我稍后检查特定类型时,所有这些都会导致一些棘手的问题.我已经改变了这个(传统的?)代码isKindOfClass,但是让我感到困扰的是我不明白这里发生了什么.

有问题的代码:

#import <objc/runtime.h>

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T') {
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "@";
}
Run Code Online (Sandbox Code Playgroud)

到底是怎么回事,为什么结果不同?

objective-c objective-c-runtime ios

5
推荐指数
1
解决办法
502
查看次数

在objective-c中,当对象本身被指定为它实现的委托时,对象如何返回不同的代理对象

我有一个实现各种协议的对象(比如10个不同的协议).

例如

@interface MyClass <UITableViewDelegate,UITableViewDataSource,UISearchDisplayDelegate,...>

@end

@implementation

/// a whole bunch of methods for the delegates
@end
Run Code Online (Sandbox Code Playgroud)

为了在这个类中"清理"东西 - 我创建了辅助类,它封装了与这些委托相关的逻辑.

所以现在新的重构类看起来像

// public interface which looks the same
@interface MyClass <UITableViewDelegate,UITableViewDataSource,UISearchDisplayDelegate,...>


@end

// private interface

@interface MyClass ()

// a bunch of objects which implement those methods
@property (nonatomic,strong) MyUITableviewDelegate *tableViewDelegate;
@property (nonatomic,strong) MyUITableviewDataSource *tableViewDelegate;
@property (nonatomic,strong) MySearchDisplayDelegate *searchDisplayDelegate;
// another bunch of objects which answer to the delegates
@end

@implementation
// all the delegate methods were moved out of …
Run Code Online (Sandbox Code Playgroud)

delegates objective-c objective-c-runtime nsinvocation ios

5
推荐指数
1
解决办法
989
查看次数

Objective-c IOS arm64方法调配失败调用原始方法

我在ARMv7 IOS设备上使用标准方法调配,它对我来说非常完美.

但是当我编译arm64的代码时 - 它无法从新方法调用原始方法

我调配的主要目的 - 在我的应用程序的内部方法中使用参数在另一种方法中.

我有原始的方法-(void)insertdata:(id)text,我想改变它,-(void)patchedCall:(id)text并在新方法中调用原始方法.

码:

static IMP sOriginalImp = NULL;

@interface TextOverrides: NSObject
+(void)load;
-(void)patchedinsert:(id)text;
@end

@implementation TextOverrides

+(void)load
{
    //Get Implementation of original method

    Class originalClass = NSClassFromString(@"DataViewController");
    Method originalMeth = class_getInstanceMethod(originalClass, @selector(insertdata:));

    //Save original method implementation
    sOriginalImp = method_getImplementation(originalMeth);

    // Get implementation of replacement method
    Method replacementMeth = class_getInstanceMethod(NSClassFromString(@"TextOverrides"), @selector(patchedCall:));

    //Replace methods
    method_exchangeImplementations(originalMeth, replacementMeth);
}

-(void)patchedCall:(id)text
{
    @synchronized(self){
        //Call of original method that we save
        sOriginalImp(self, @selector(insertdata:), text);

        //Make …
Run Code Online (Sandbox Code Playgroud)

objective-c objective-c-runtime ios arm64 method-swizzling

5
推荐指数
1
解决办法
507
查看次数

回到sel_getUid()的原始行为

TL; DR:如何检查具有给定名称的选择器是否已注册,而不实际注册?

谢谢!


嗨,我有一个Objective-C应用程序和一堆NSObject,通过用objc编写的简单代理库导出到Lua状态.所有Lua方面的电话都是这样的:

exported_objc_object:myMethodName(...)

-- same as --
exported_objc_object.myMethodName(exported_objc_object, ...)

-- same as --
key = 'myMethodName'
exported_objc_object[key](exported_objc_object, ...)
Run Code Online (Sandbox Code Playgroud)

转发好像有人打电话:

[objc_object lua_myMethodName:L];

// declared as
- (int)lua_myMethodName:(lua_State *)L { ... }
Run Code Online (Sandbox Code Playgroud)

实际上,Lua导出对象上的任何"get"操作码都会返回一个缓存的Lua闭包,在调用时会通过使用sprintf(s, "lua_%s:", key))&& sel_getUid(s)(包括所有检查)构造的选择器调用相应的Objective-C方法.如果生成的选择器没有实现-[respondsToSelector:],那么exported_objc_object.myMethodName只需返回nil.

显然,代理库必须通过sel_getUid()sel_registerName()(我相信两者@selectorNSSelectorFromString()最终在那里)进行动态查找.手册说明了sel_getUid()用于查找选择器名称(而不是立即将它们注册到SEL注册表中),但它的现代实现现在与sel_registerName()由于当时某人的代码中的错误相同.

我可以坚持sel_registerName()行为,但这留下了内存吃攻击向量,因为一些恶意脚本可能会开始通过object[makeRandomKey()]循环中的sml查找长的随机/无效选择器,从而永远溢出SEL注册表.如果sel_getUid()按计划工作,代理lib将能够测试选择器的存在,然后实际检查对象是否响应它,而无需过多注册.但事实并非如此.

objective-c objective-c-runtime selector

5
推荐指数
1
解决办法
263
查看次数

为什么Apple的KVO实现使用子类而不是调配?

在Apple的Key-Value Observing Implementation Details文档中,它表示实现创建了一个转发setter方法的子类.子类替换原始类.

为什么不使用混合method_exchangeImplementations()方法呢?为什么创建子类是必要的?

objective-c objective-c-runtime key-value-observing

5
推荐指数
1
解决办法
180
查看次数