Giter Club home page Giter Club logo

swifttrace's Introduction

SwiftTrace

Trace Swift and Objective-C method invocations of non-final classes in an app bundle or framework. Think Xtrace but for Swift and Objective-C.

SwiftTrace is most easily used as a CocoaPod and can be added to your project by temporarily adding the following line to it's Podfile:

pod 'SwiftTrace'

This project has been updated to Swift 3 from the Xocde 8 beta. If you want to use the Swift2 branch:

pod 'SwiftTrace', '2.1'

Once the project has rebuilt import SwiftTrace into the application's AppDelegate and add something like the following to the beginning of it's didFinishLaunchingWithOptions method:

SwiftTrace.traceBundleContaining( aClass: self.dynamicType )

This traces all classes defined in the main application bundle. To trace, for example, all classes in the RxSwift framework add the following

SwiftTrace.traceBundleContaining( aClass: RxSwift.DisposeBase.self )

This gives output in the Xcode debug console something like:

RxSwift.SingleAssignmentDisposable.dispose () -> ()
RxSwift.SingleAssignmentDisposable.disposable.setter : RxSwift.Disposable11
RxSwift.CompositeDisposable.addDisposable (RxSwift.Disposable11) -> Swift.Optional<RxSwift.BagKey>
RxSwift.CurrentThreadScheduler.schedule <A> (A, action : (A) -> RxSwift.Disposable11) -> RxSwift.Disposable11
-[RxSwift.CurrentThreadSchedulerKey copyWithZone:] -> @24@0:8^v16
RxSwift.CompositeDisposable.addDisposable (RxSwift.Disposable11) -> Swift.Optional<RxSwift.BagKey>
RxSwift.CompositeDisposable.addDisposable (RxSwift.Disposable11) -> Swift.Optional<RxSwift.BagKey>
RxSwift.SerialDisposable.disposable.setter : RxSwift.Disposable11
RxSwift.SingleAssignmentDisposable.dispose () -> ()
RxSwift.SingleAssignmentDisposable.disposable.setter : RxSwift.Disposable11
RxSwift.SingleAssignmentDisposable.dispose () -> ()
RxSwift.CompositeDisposable.removeDisposable (RxSwift.BagKey) -> ()
RxSwift.SingleAssignmentDisposable.dispose () -> ()

The line beginning "-[RxSwift" is where the old Objective-C dynamic dispatch is being used.

To trace a system framework such as UIKit you can trace classes using a pattern:

SwiftTrace.traceClassesMatching( pattern:"^UI" )

Individual classes can be traced using the underlying:

SwiftTrace.trace( aClass: MyClass.self )

Output can be filtered using inclusion and exclusion regexps.

SwiftTrace.include( pattern: "TestClass" )
SwiftTrace.exclude( pattern: "\\.getter" )

These methods must be called before you start the trace as they are applied during the "Swizzle". There is a default set of exclusions setup as a result of testing, tracing UIKit.

public let swiftTraceDefaultExclusions = "\\.getter|retain]|_tryRetain]|_isDeallocating]|^\\+\\[(Reader_Base64|UI(NibStringIDTable|NibDecoder|CollectionViewData|WebTouchEventsGestureRecognizer)) |^.\\[UIView |UIButton _defaultBackgroundImageForType:andState:|RxSwift.ScheduledDisposable.dispose"

If you want to further process output you can define a custom tracing class:

class MyTracer: SwiftTraceInfo {

    override func trace() -> IMP {
        print( ">> "+symbol )
        return original /// must return implmentation to call
    }
    
}

SwiftTrace.tracerClass = MyTracer.self

How it works

A Swift AnyClass instance has a layout similar to an Objective-C class with some additional data documented in the ClassMetadataSwift in SwiftTrace.swift. After this data there is a vtable of pointers to the class and instance member functions of the class up to the size of the class instance. SwiftTrace replaces these function pointers with a pointer to a unique assembly language "trampoline" entry point which has destination function and data pointers associated with it. Registers are saved and this function is called passing the data pointer to log the method name. The method name is determined by de-mangling the symbol name associated the function address of the implementing method. The registers are then restored and control is passed to the original function implementing the method.

Please file an issue if you encounter a project that doesn't work while tracing. It should be 100% reliable as it uses assembly language trampolines rather than Swizzling like Xtrace. Otherwise, the author can be contacted on Twitter @Injection4Xcode. Thanks to Oliver Letterer for imp_implementationForwardingToSelector used to set up the trampolines.

Enjoy!

swifttrace's People

Contributors

johnno1962 avatar

Watchers

Ivan Kh avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.