我有一个关于在Objective-C中使用星号的问题.需要明确的是:我理解指针是什么以及程序C中的所有内容.我想知道两件事情:
1)为什么所有(引用)Objective-C对象指针?为什么不是普通变量?(即NSArray数组= [[NSArray alloc] init];)
2)为什么在调用方法时省略星号?
谢谢!
首先,我想明确我不是在谈论定义一个协议,而是我理解它的概念
@protocol someprotocol
- (void)method;
@end
Run Code Online (Sandbox Code Playgroud)
我知道Obj-C运行时允许在RUNTIME中创建类,以及它的ivars和方法.也可用于创建SEL-s.我想我只是遗漏了一些东西,但有没有人知道在运行时调用什么函数来创建协议?这个的主要原因是conformsToProtocol:工作,所以只是添加适当的方法并没有真正削减它.
我想要实现Xcode 3中的"修复和继续功能".
背景:
主要思想是:当我需要"快速修复某些东西"时,我不会重新编译,投射.我正在Attacker class使用'updated'方法实现编译小,将其加载到内存中并替换incorrect在运行时实现的VictimClass方法.我认为这个方法可以更快地完成整个项目的重新编译.
当我完成修复时,我只是将Attacker class方法的来源复制到Victim class.
问题
目前,我不知道如何[super ...]在Attacker类中正确调用.
例如,我有VictimClass
@interface VictimClass : UIView @end
@implementation VictimClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
@end
@interface AttackerClass : NSObject @end
@implementation AttackerClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPrettyBackground];
}
@end
....
// EXCHANGE IMPLEMENTATIONS
Method m = class_getInstanceMethod([AttackerClass class], @selector(drawRect:));
const char * types = method_getTypeEncoding(m);
IMP attackerImp = method_getImplementation(m);
class_replaceMethod([VictimClass class], @selector(drawRect:), attackerImp, types);
// Invoking …Run Code Online (Sandbox Code Playgroud) 在Objective-C中,至少有两种方法可以获得(或创建?因此问题)一个选择器:@selector(foo:bar:),或NSSelectorFromString(@"foo:bar:").但是选择器的生命周期是多少?
由于选择器(至少)知道它们的名称,因此它们不太可能是可以在程序周围移动的固定大小的可复制值.这意味着有人需要分配并可能解除分配它们.来自Cocoa框架的大多数对象都具有retain-release语义,这使得它们的所有权显而易见并且相对容易跟踪.但是,我认为没有明确的选择权所有权概念.
我希望使用第一种语法获得的选择器在程序的整个生命周期中都是全局的(比如文字字符串),但是另一种呢?如果我创建/获取选择器NSSelectorFromString(@"foo:bar:"),它是否也适用于我的程序的整个生命周期?
我花了相当长的一段时间,试图找出如何class_respondsToSelector以及respondsToSelector会产生不同的结果.考虑以下课程:
@interface Dummy : NSObject
- (void)test;
@end
@implementation Dummy
- (void)test {}
@end
Run Code Online (Sandbox Code Playgroud)
我的情况是我尝试确定一个类是否响应某个类方法.这件作品再现了这个问题:
Class class = [Dummy class];
if (class_respondsToSelector(class, @selector(test)))
NSLog(@"class_respondsToSelector: YES");
else
NSLog(@"class_respondsToSelector: NO");
if ([class respondsToSelector:@selector(test)])
NSLog(@"respondsToSelector: YES");
else
NSLog(@"respondsToSelector: NO");
Run Code Online (Sandbox Code Playgroud)
如果我删除声明和实现-test,上面的输出是NO和NO按预期.但是,在读取上面(包括-test)时运行它,产生的输出如下:
class_respondsToSelector:是的
respondsToSelector:没有
文档没有说明是否respondsToSelector仅适用于实例,只是它指示接收器是否实现...,因此我无法确定这是否是正确的行为.我错过了什么吗?
更新
我有以下汇编代码(NASM)
global _main
extern _sizeof
extern _printf
extern _objc_msgSend
extern _objc_getClass
extern _sel_registerName
SECTION .data
alert_text : db "NSAlert", 0
alloc_sel : db "alloc", 0
init_sel : dw "init", 0
alert_class: resb 4
SECTION .text
_main:
; get the class
sub esp, 8
push alert_text
call _objc_getClass
add esp, 12
; save class
mov dword [alert_class], eax
; get alloc selector
sub esp, 8
push alloc_sel
call _sel_registerName
add esp, 12
; allocate it
sub esp, 4
push alloc_sel
; …Run Code Online (Sandbox Code Playgroud) 当我使用时objc_setAssociatedObject,我知道是使用保留还是分配,但我不知道如何在OBJC_ASSOCIATION_RETAIN和之间做出决定OBJC_ASSOCIATION_RETAIN_NONATOMIC.何时应该使用其中一种?
我在其中一个项目中发现了一个奇怪的问题.我的目标是在运行时添加一个带有新协议的新类.我拿出了部分代码来重现这个问题.
- (void)viewDidLoad {
[super viewDidLoad];
[self registerClass:@"Daidouji"];
[self protocolInClass:NSClassFromString(@"Daidouji")];
}
- (void)registerClass:(NSString *)className {
Class superclass = (Class)objc_getClass("UIViewController");
Class newClass = objc_allocateClassPair(superclass, [className UTF8String], 0);
Protocol *newProtocol = objc_allocateProtocol([@"ViewController" UTF8String]);
objc_registerProtocol(newProtocol);
class_addProtocol(newClass, newProtocol);
objc_registerClassPair(newClass);
}
- (void)protocolInClass:(Class)cls {
unsigned count;
__unsafe_unretained Protocol **protocols = class_copyProtocolList(cls, &count);
if (count) {
NSLog(@"%@", [NSString stringWithUTF8String:protocol_getName(protocols[0])]);
}
free(protocols);
}
Run Code Online (Sandbox Code Playgroud)
在iPhone5(armv7)或iOS模拟器(i386/x86_64)中,NSLog可以很好地打印ViewController.在iPhone5s(arm64)中,应用程序将崩溃或打印(null).
我发现的第一个解决方案是添加protocol_getName之类的
- (void)registerClass:(NSString *)className {
Class superclass = (Class)objc_getClass("UIViewController");
Class newClass = objc_allocateClassPair(superclass, [className UTF8String], 0);
Protocol …Run Code Online (Sandbox Code Playgroud) 之前有人问过同样的问题:Objective-C运行时:为class_addIvar的大小和对齐放什么? 但它还没有完全解决.
函数声明如下:
BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *types)
Run Code Online (Sandbox Code Playgroud)
用于将实例变量添加到Objective-C中动态创建的类.
第四个论点uint8_t alignment在Apple的文档中描述:
The instance variable's minimum alignment in bytes is 1<<align. The minimum alignment of an instance variable depends on the ivar's type and the machine architecture. For variables of any pointer type, pass log2(sizeof(pointer_type)).
在一些教程中,它只是声称如果ivar是指针类型,我应该使用log2(sizeof(pointer_type)); 如果ivar是值类型,我应该使用sizeof(value_type).但为什么?有人可以详细解释一下吗?
通过Selector调用的方法不遵守默认参数值。
例
如果我连接了一个按钮以通过选择器调用函数:
func setupButton() {
self.button.addTarget(self, action: #selector(printValue), for: .touchUpInside)
}
@objc func printValue(value:Int = 7)
{
if value == 7 {
print("received default")
} else {
print("default unused")
}
}
Run Code Online (Sandbox Code Playgroud)
通过代码调用此方法时,将打印“ received default”,但是当我按下按钮并通过选择器调用该方法时,将显示“默认未使用”,因为未将7设置为该值。
为什么会这样呢?