Catch UIViewAlertForUnsatisfiableConstraints en la producción

¿Es posible capturar las ambigüedades de la restricción automática en la producción, el equivalente a un UIViewAlertForUnsatisfiableConstraints interrupción UIViewAlertForUnsatisfiableConstraints pero para las aplicaciones de producción?

Mi objective sería agregar un controller global que reportaría dichos errores a un sistema de logging.

El símbolo UIViewAlertForUnsatisfiableConstraints realidad es una function:

_UIViewAlertForUnsatisfiableConstraints(NSLayoutConstraint* unsatisfiableConstraint, NSArray<NSLayoutConstraint*>* allConstraints) .

Es privado, por lo que no puede replacelo.

Pero se llama desde un método privado -[UIView engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:] , que puede ser swizzled. Este método tiene aproximadamente este contenido:

 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); } } } 

Si entiendo correctamente de este artículo , __UIConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints siempre devolverá NO en iOS, por lo que todo lo que necesita hacer es verificar la propiedad bool privada llamada _isUnsatisfiableConstraintsLoggingSuspended y luego llamar al método original.

Este es el ejemplo del código de resultado:

 #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 

Funciona en iOS 8.2 / 9/10 (no funciona en iOS 8.1, así que ten cuidado), pero no puedo ofrecer ninguna garantía. Además, atrapa problemas de restricción en los componentes del sistema, como el keyboard / reproductor de video / etc. Este código es frágil (puede provocar errores en cualquier actualización de la versión del sistema, cambio de parameters, etc.) y no recomendaré utilizarlo en producción (supongo que no pasará incluso el process de revisión automática). Tienes la última palabra, pero estás advertido.

Sin embargo, creo que puedes utilizarlo en comstackciones para probadores internos / externos para corregir errores en la reproducción automática antes de la producción.

Se notó que está utilizando swift: puede agregar este código a su proyecto rápido con un file de encabezado de puenteo.

La respuesta corta es que se trata de una API privada y no deberías estar jugando con ella en el código de producción …

… al less no sin conocer los peligros relacionados:

R) Apple rechazará su aplicación si intenta anular SPI como este en un producto enviado a la tienda de aplicaciones. Y si se desliza por alguna razón, la atraparán en alguna date posterior, y eso generalmente es peor.

B) El método de swizzling, al igual que @Roman menciona en su respuesta, a menudo conlleva la posibilidad de que desestabilices en lo que sea que estés trabajando (o en el futuro). Todavía me preocupa cuando utilizo una biblioteca de terceros que alguien está haciendo algo frágil como este bajo el capó.

Con esas advertencias por ahí, siga adelante, anule los methods privados y conviértalos en contenido de corazón. Solo por favor no envíe ese código.