我想知道UIViewAlertForUnsatisfiableConstraints是否是我可以使用的选择器。到目前为止,我只知道UIViewAlertForUnsatisfiableConstraints是一个符号,可以用来放置一个符号断点。但我在任何公共课堂上都找不到这个符号。有人知道它的位置吗?
请注意,我希望在单元测试中这样做,而不是在生产代码中。
发布于 2015-09-20 08:41:58
由于UIViewAlertForUnsatisfiableConstraints是一个C函数,因此对它进行处理比典型的Objective方法需要更多的工作。
最简单的(大多数消息来源都说这是唯一可能的方法)是通过基板的MSHookFunction,然而,这需要一个越狱手机。如果这是一个有效的选项,我建议使用它来简单地挂起函数。
在非越狱环境中,需要高级运行时操作。由于某种原因,我真的很喜欢浪费时间来学习一门很快就会死掉的语言。因此,这是完整的解决方案!这个链接是一个巨大的帮助。
#import <dlfcn.h>
#import <objc/runtime.h>
#include <sys/mman.h>
int64_t originalOffset;
int64_t *origFunc;
void swizzled_UIViewAlertForUnsatisfiableConstraints(NSLayoutConstraint *offendingConstraint, NSArray *allConstraints) {
// inject swizzle code here
NSLog(@"swizzled!");
// call the original function (if you want!)
if (origFunc) {
// replace jump instruction w/ the original memory offset
*origFunc = originalOffset;
((void(*)(NSLayoutConstraint*, NSArray*))origFunc)(offendingConstraint, allConstraints);
}
}
static inline BOOL swizzleAlertForUnsatisfiableConstraints() {
// get the original function and hold onto it's memory offset
origFunc = dlsym(RTLD_DEFAULT, "UIViewAlertForUnsatisfiableConstraints");
if (!origFunc) {
return NO;
}
originalOffset = *origFunc;
// define the swizzled implementation
int64_t *swizzledFunc = (int64_t*)&swizzled_UIViewAlertForUnsatisfiableConstraints;
// make the memory containing the original funcion writable
size_t pageSize = sysconf(_SC_PAGESIZE);
uintptr_t start = (uintptr_t)origFunc;
uintptr_t end = start + 1;
uintptr_t pageStart = start & -pageSize;
mprotect((void *)pageStart, end - pageStart, PROT_READ | PROT_WRITE | PROT_EXEC);
//Calculate the relative offset needed for the jump instruction
//Since relative jumps are calculated from the address of the next instruction,
// 5 bytes must be added to the original address (jump instruction is 5 bytes)
int64_t offset = (int64_t)swizzledFunc - ((int64_t)origFunc + 5 * sizeof(char));
//Set the first instruction of the original function to be a jump
// to the replacement function.
//E9 is the x86 opcode for an unconditional relative jump
int64_t instruction = 0xe9 | offset << 8;
*origFunc = instruction;
return YES;
}发布于 2015-11-03 15:23:33
我试过凯西的解决方案,效果很好,但只在模拟器上。ARM处理器有拇指模式,因此使用ARM B指令比使用x86 JMP要困难得多。
UIViewAlertForUnsatisfiableConstraints是从UIView的下面方法调用的。它似乎是在内部引擎委托中定义的。
- (void)engine:(NSISEngine *)arg1 willBreakConstraint:(id <NSISConstraint>)arg2 dueToMutuallyExclusiveConstraints:(NSArray *)arg3;Swizzling方法比C func容易得多。
定义专用接口:
@interface UIView (UIConstraintBasedLayout_EngineDelegate_PrivateInterface)
- (void)engine:(id /* NSISEngine */)engine willBreakConstraint:(NSLayoutConstraint *)breakConstraint dueToMutuallyExclusiveConstraints:(NSArray<NSLayoutConstraint *> *)mutuallyExclusiveConstraints;
@end然后,swizzle objc方法:
+ (void)swizzleAutoLayoutAlertMethod
{
Class class = [UIView class];
Method originalMethod = class_getInstanceMethod(class, @selector(engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:));
if (!originalMethod) {
[NSException raise:NSInternalInconsistencyException format:@"This platform does not support Auto Layout or interface has been changed."];
}
Method swizzledMethod = class_getInstanceMethod(class, @selector(swizzled_engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:));
method_exchangeImplementations(swizzledMethod, originalMethod);
}注意:我创建了用于自动布局的林特库,参考https://github.com/ypresto/AutoLayoutLint。
https://stackoverflow.com/questions/32671327
复制相似问题