Comment désactiver la journalisation?

J'ai une application qui utilise la class UITextChecker fournie par Apple. Cette class a un bug suivant: Si le périphérique iOS est hors ligne (devrait être souvent pour mon application) chaque fois que j'appelle certaines des methods de UITextChecker , il se connecte à la console:

 2016-03-08 23:48:02.119 HereIsMyAppName [4524:469877] UITextChecker sent ssortingng:isExemptFromTextCheckerWithCompletionHandler: to com.apple.TextInput.rdt but received error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.TextInput.rdt was invalidated." 

Je ne veux pas avoir de journaux spammés par ces messages. Y at-il un moyen de désactiver la journalisation du code? Je désactiverais la journalisation avant appel à l'une des methods de UITextChecker et la réactiverais ensuite. Ou y a-t-il un moyen de désactiver la journalisation sélective par class (événement si ce n'est pas la class de base)? Ou toute autre solution?

Avertissement : Cette réponse utilise les fonctions Cocoa C privées, mais encore documentées, _NSSetLogCSsortingngFunction() et _NSLogCSsortingngFunction() .

_NSSetLogCSsortingngFunction() est une interface créée par Apple pour gérer la fonction d'implémentation de NSLog . Il a été initialement exposé pour que WebObjects se connecte aux instructions NSLog sur les machines Windows, mais existe toujours dans les API iOS et OS X d'aujourd'hui. Il est documenté dans cet article de support.

La fonction prend un pointeur de fonction avec les arguments const char* message , la string à consigner, la unsigned length , la longueur du message et un BOOL withSysLogBanner qui bascule la bannière de journalisation standard. Si nous créons notre propre fonction de hook pour la journalisation qui ne fait rien (une implémentation vide plutôt que d'appeler NSLog comme NSLog fait en coulisses), nous pouvons désactiver toute la journalisation de votre application.

Exemple Objective-C (ou Swift avec en-tête de pontage):

 extern void _NSSetLogCSsortingngFunction(void(*)(const char*, unsigned, BOOL)); static void hookFunc(const char* message, unsigned length, BOOL withSysLogBanner) { /* Empty */ } // Later in your application _NSSetLogCSsortingngFunction(hookFunc); NSLog(@"Hello _NSSetLogCSsortingngFunction!\n\n"); // observe this isn't logged 

Un exemple d'implémentation de ceci peut être trouvé dans YILogHook , qui fournit une interface pour append un tableau de blocs à n'importe NSLog instruction NSLog (écrire dans un file, etc.).

Exemple de Swift pur:

 @asmname("_NSSetLogCSsortingngFunction") // NOTE: As of Swift 2.2 @asmname has been renamed to @_silgen_name func _NSSetLogCSsortingngFunction(_: ((UnsafePointer<Int8>, UInt32, Bool) -> Void)) -> Void func hookFunc(message: UnsafePointer<Int8>, _ length: UInt32, _ withSysLogBanner: Bool) -> Void { /* Empty */ } _NSSetLogCSsortingngFunction(hookFunc) NSLog("Hello _NSSetLogCSsortingngFunction!\n\n"); // observe this isn't logged 

Dans Swift, vous pouvez également choisir d'ignorer tous les parameters du bloc sans utiliser hookFunc comme ceci:

 _NSSetLogCSsortingngFunction { _,_,_ in } 

Pour réactiver la journalisation avec Objective-C, transmettez simplement NULL comme pointeur de fonction:

 _NSSetLogCSsortingngFunction(NULL); 

Avec Swift, les choses sont un peu différentes, puisque le compilateur se plaindra d'une incompatibilité de type si nous essayons de passer en nil ou un pointeur nil ( NULL n'est pas disponible dans Swift). Pour résoudre ce problème, nous devons accéder à une autre fonction système, _NSLogCSsortingngFunction , pour get un pointeur vers l'implémentation de journalisation par défaut, conserver cette reference lorsque la journalisation est désactivée et définir la reference lorsque nous souhaitons réactiver la journalisation.

J'ai nettoyé l'implémentation de Swift en ajoutant un typedef NSLogCSsortingngFunc :

 /// Represents the C function signature used under-the-hood by NSLog typealias NSLogCSsortingngFunc = (UnsafePointer<Int8>, UInt32, Bool) -> Void /// Sets the C function used by NSLog @_silgen_name("_NSSetLogCSsortingngFunction") // NOTE: As of Swift 2.2 @asmname has been renamed to @_silgen_name func _NSSetLogCSsortingngFunction(_: NSLogCSsortingngFunc) -> Void /// Resortingeves the current C function used by NSLog @_silgen_name("_NSLogCSsortingngFunction") func _NSLogCSsortingngFunction() -> NSLogCSsortingngFunc let logFunc = _NSLogCSsortingngFunction() // get function pointer to the system log function before we override it _NSSetLogCSsortingngFunction { (_, _, _) in } // set our own log function to do nothing in an anonymous closure NSLog("Observe this isn't logged."); _NSSetLogCSsortingngFunction(logFunc) // switch back to the system log function NSLog("Observe this is logged.")