Symbol UIViewAlertForUnsatisfiableConstraints
rzeczywiście jest funkcją:
_UIViewAlertForUnsatisfiableConstraints(NSLayoutConstraint* unsatisfiableConstraint, NSArray<NSLayoutConstraint*>* allConstraints)
.
To jest prywatne, więc nie można go zastąpić.
Ale jest wywoływana z prywatnej metody -[UIView engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:]
, którą można przekręcić. Metoda ta ma w przybliżeniu tę zawartość:
void -[UIView engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:] {
if ([self _isUnsatisfiableConstraintsLoggingSuspended]) {
[self _recordConstraintBrokenWhileUnsatisfiableConstraintsLoggingSuspended:$arg4]; // add constraint to some pool
}
else {
if (__UIConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints) {
// print something in os_log
}
else {
_UIViewAlertForUnsatisfiableConstraints($arg4, $arg5);
}
}
}
Jeśli dobrze rozumiem, ze this article, __UIConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints
zawsze nie zwraca na iOS, więc wszystko co musisz zrobić, to sprawdzić prywatną własność bool nazwie _isUnsatisfiableConstraintsLoggingSuspended
a następnie wywołać metodę oryginalnego.
To jest przykład kodu wynikowego:
#import <objc/runtime.h>
void SwizzleInstanceMethod(Class classToSwizzle, SEL origSEL, Class myClass, SEL newSEL) {
Method methodToSwizzle = class_getInstanceMethod(classToSwizzle, origSEL);
Method myMethod = class_getInstanceMethod(myClass, newSEL);
class_replaceMethod(classToSwizzle, newSEL, method_getImplementation(methodToSwizzle), method_getTypeEncoding(methodToSwizzle));
class_replaceMethod(classToSwizzle, origSEL, method_getImplementation(myMethod), method_getTypeEncoding(myMethod));
}
@interface InterceptUnsatisfiableConstraints : NSObject
@end
@implementation InterceptUnsatisfiableConstraints
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL willBreakConstantSel = NSSelectorFromString(@"engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:");
SwizzleInstanceMethod([UIView class], willBreakConstantSel, [self class], @selector(pr_engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:));
});
}
- (void)pr_engine:(id)engine willBreakConstraint:(NSLayoutConstraint*)constraint dueToMutuallyExclusiveConstraints:(NSArray<NSLayoutConstraint*>*)layoutConstraints {
BOOL constrainsLoggingSuspended = [[self valueForKey:@"_isUnsatisfiableConstraintsLoggingSuspended"] boolValue];
if (!constrainsLoggingSuspended) {
NSLog(@"_UIViewAlertForUnsatisfiableConstraints would be called on next line, log this event");
}
[self pr_engine:engine willBreakConstraint:constraint dueToMutuallyExclusiveConstraints:layoutConstraints];
}
@end
To działa na iOS 8.2/9/10 (nie działa w iOS 8.1, więc należy być ostrożnym), ale nie mogę dać żadnej gwarancji. Ponadto przechwytuje problemy z ograniczeniami w komponentach systemu, takich jak klawiatura/odtwarzacz wideo/itp. Ten kod jest delikatny (może prowadzić do awarii w przypadku każdej aktualizacji wersji systemu, zmiany parametrów itp.) I nie polecam używania go w produkcji (zgadnij, że nie przejdzie on nawet zautomatyzowanym procesem recenzowania). Masz ostatnie słowo, ale jesteś ostrzeżony.
Jednak myślę, że można go używać w kompilacjach dla wewnętrznych/zewnętrznych testerów, aby naprawić błędy w autolayout przed rozpoczęciem produkcji.
Zauważono, że korzystasz z szybkiego: możesz dodać ten kod do swojego szybkiego projektu z pomostowym plikiem nagłówkowym.
To jest dobre pytanie. Jak rozumiem, symboliczne punkty przerwania umożliwiają złamanie określonego symbolu, metody lub selektora.Próbowałem externing globalnej funkcji C 'UIViewAlertForUnsatisfiableConstraints()' i patrząc, czy to jest instancja lub metoda klasy na 'UIView', ale nie znalazłem nic do tej pory. – JAL