A Swift tool designed to capture and analyze Objective-C message sends during code execution.
When calling methods on Objective-C objects, i.e. [NSString alloc], the Objective-C runtime uses the objc_msgSend function to lookup the method implementation and call it.
Using "swizzling" the implementation called by objc_msgSend can be replaced with a custom implementation.
Swift itself does not use the objc_msgSend function, so it does not support swizzling.
But many Swift frameworks use Objective-C runtime features, e.g. @objc methods, NSObject methods, etc.
This tool leverages the Objective-C runtime's message logging capability to help debug and understand Objective-C message patterns in your code.
Before using this tool, you need to enable Objective-C message logging by setting the following environment variable NSObjCMessageLoggingEnabled to YES. This will create a file at /tmp/msgSends-<PID> where the messages will be logged (see Apple Technote TN2124 for more details).
Objective-C message logging is only available in debug builds for macOS. It appears to not be available on iOS or the simulator.
- Clone this repository
- Open
Package.swiftwith Xcode - Edit the
main.swiftfile to add your code block to execute, i.e.:
let logs = try collectLogs {
let _ = NSString("Hello World")
}- Make sure the environment variable for the Run scheme is set:
NSObjCMessageLoggingEnabled=YES- Run the analyzer
The analyzer performs the following steps:
- Opens the message log file at
/tmp/msgSends-<PID> - Executes your code block
- Captures all Objective-C messages sent during execution
- Prints the collected logs
The tool is designed to minimize its own impact on the logged messages by:
- Using C-level file operations instead of higher-level APIs
- Preparing data structures before the analysis
- Capturing only new messages during the execution block
This is an example code block that will be executed (see main.swift):
let logs = try collectLogs {
let _ = NSString("Hello World")
}The output will something look like this:
+-----------------+
| COLLECTED LOGS: |
+-----------------+
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytesNoCopy:length:encoding:freeWhenDone:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithString:
- __NSCFString __NSCFString release
- __NSCFString __NSCFString release
Based on this output, you can see that the NSString class is allocated twice, and the NSPlaceholderString class is allocated once.
In addition string literals are allocated as __NSCFString instances and released twice.