我正在定义一个自定义协议:
@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) 我NSManagedObject在单元测试中创建了一堆简单的s.它们只有一个name类型的属性NSString *.我总是给我NSManagedObject相同entityName和Class名字.
我想避免编写以下代码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的运行时类型 …
在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运行时库,当消息发送到不响应它的对象时,运行时系统为接收者提供了另一个处理消息的机会.因此,接收者的forward::方法(如果实现的话)被调用.但是,看看NSObject.mm,NSObject似乎没有实现forward::.
那么,如何NSObject的forwardInvocation:方法被调用,因为需要转发时运行系统调用的唯一的事情是forward::?Foundation是否使用objc_setForwardHandler(runtime.h)设置一个新的处理程序,forwardInvocation:只要发送到NSObject对象的消息需要转发,它就会调用?
forwarding objective-c objective-c-runtime nsobject nsinvocation
如果我在里面创建一个单例+[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
似乎我们使用的应用程序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)
到底是怎么回事,为什么结果不同?
我有一个实现各种协议的对象(比如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) 我在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) 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()(我相信两者@selector并NSSelectorFromString()最终在那里)进行动态查找.手册说明了sel_getUid()用于查找选择器名称(而不是立即将它们注册到SEL注册表中),但它的现代实现现在与sel_registerName()由于当时某人的代码中的错误相同.
我可以坚持sel_registerName()行为,但这留下了内存吃攻击向量,因为一些恶意脚本可能会开始通过object[makeRandomKey()]循环中的sml查找长的随机/无效选择器,从而永远溢出SEL注册表.如果sel_getUid()按计划工作,代理lib将能够测试选择器的存在,然后实际检查对象是否响应它,而无需过多注册.但事实并非如此.
在Apple的Key-Value Observing Implementation Details文档中,它表示实现创建了一个转发setter方法的子类.子类替换原始类.
为什么不使用混合method_exchangeImplementations()方法呢?为什么创建子类是必要的?
objective-c ×10
ios ×4
nsinvocation ×2
arm64 ×1
c ×1
concurrency ×1
delegates ×1
forwarding ×1
nsobject ×1
selector ×1