Skip to content
This repository has been archived by the owner on Nov 12, 2019. It is now read-only.

Commit

Permalink
Merge pull request #10 from samodom/develop
Browse files Browse the repository at this point in the history
Updated method swizzling interface
  • Loading branch information
samodom authored Nov 20, 2016
2 parents 115ac21 + 3b97cd4 commit 4d15fe3
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 98 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
FoundationSwagger Changelog
===========================

### v0.2.4 (November 19, 2016)
- Updated method swizzling interface


### v0.2.3 (November 19, 2016)
- Correctly corrected default object association policy


### v0.2.2 (November 17, 2016)
- Corrected default object association policy

Expand Down
82 changes: 66 additions & 16 deletions Docs/MethodSwizzling.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,77 @@ class MethodAssociation {

## Swizzling

In order to swizzle a method to use an alternate implementation, the idea of replacing an *original* method with a *replacement* method is codified in the API with two separate methods:
In order to swizzle a method to use an alternate implementation, the idea of replacing an *original* method implementation with a *replacement* method implementation is codified in the API with four separate methods.


### With top-level context

```swift
let realSelector = #selector(UIViewController.viewWillAppear(_:))
let mySelector = #selector(UIViewController.my_viewWillAppear(_:))
/// To start using the alternate implementation
/// in place of the original:
association.useAlternateImplementation()

/// Code executed here will use *swapped*
/// implementations for the two selectors

/// To restore the original implementation:
association.useOriginalImplementation()

/// Code executed here will use the *original*
/// implementations of the two selectors
```

let association = MethodAssociation(
forClass: UIViewController.self,
ofType: .instance,
originalSelector: realSelector,
alternateSelector: mySelector
)
### With nested context

/// To start using replacement method in place of original:
association.useAlternateMethod()
```swift
/// To automatically gate the replacement and
/// restoration in a single closure:
association.withAlternateImplementation() {
/// Code executed here will use *swapped*
/// implementations for the two selectors
}
```

/// To restore the original method implementation:
association.useOriginalMethod()
Or while using the alternate implementation:

/// Or, to automatically gate the replacement and restoration in a single closure:
association.useAlternateMethod() {
/// your code here
```swift
association.useAlternateImplementation()

association.withOriginalImplementation() {
/// Code executed here will use the *original*
/// implementations of the two selectors
}

association.useOriginalImplementation()
```

### Using any combination safely

```swift
/// Any series and mixture of these methods can
/// be used without methods being swizzled incorrectly
association.withAlternateImplementation() {
/// Code executed here will use *swapped*
/// implementations for the two selectors

/// This call will be ignored since the
/// implementations are already swapped
self.association.useAlternateImplementation()

self.association.withOriginalImplementation()
/// Code executed here will use the *original*
/// implementations of the two selectors
}

/// Restoring the original implementation for a while
association.useOriginalImplementation()

/// Code executed here will use the *original*
/// implementations of the two selectors

}

/// Even though we didn't explicitly restore
/// the original implementations, they will be
/// restored automatically for us
```
38 changes: 30 additions & 8 deletions FoundationSwagger/MethodSwizzling/MethodSwizzling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,49 @@ public typealias NullaryVoidClosure = () -> Void

public extension MethodAssociation {

/// Swizzles the original and alternate methods of the association so that the
/// alternate method is used when the original selector is called.
public func useAlternateImplementation() {
guard !isSwizzled else { return }
swapImplementations()
}


/// Swizzles the original and alternate methods of the association so that the
/// alternate method is used when the original selector is called.
/// - parameter context: Closure to execute while the alternate method implementation is being used.
public func useAlternateImplementation(context: NullaryVoidClosure? = nil) {
public func withAlternateImplementation(context: NullaryVoidClosure) {
guard !isSwizzled else { return }
useAlternateImplementation()
context()
useOriginalImplementation()
}


/// Swizzles the original and alternate methods of the association so that the
/// original method is used when the original selector is called.
public func useOriginalImplementation() {
guard isSwizzled else { return }
swapImplementations()
context?()
}


/// Swizzles the original and alternate methods of the association so that the
/// original method is used when the original selector is called.
/// - parameter context: Closure to execute while the original method implementation is being used.
public func useOriginalImplementation(context: NullaryVoidClosure? = nil) {
public func withOriginalImplementation(context: NullaryVoidClosure) {
guard isSwizzled else { return }

swapImplementations()
context?()
useOriginalImplementation()
context()
useAlternateImplementation()
}

private func swapImplementations() {
}


fileprivate extension MethodAssociation {

func swapImplementations() {
method_exchangeImplementations(
methodForSelector(originalSelector),
methodForSelector(alternateSelector)
Expand All @@ -41,7 +63,7 @@ public extension MethodAssociation {
isSwizzled = !isSwizzled
}

private func methodForSelector(_ selector: Selector) -> Method {
func methodForSelector(_ selector: Selector) -> Method {
switch methodType {
case .class:
return class_getClassMethod(owningClass, selector)
Expand Down
Loading

0 comments on commit 4d15fe3

Please sign in to comment.