Skip to content

Commit

Permalink
Merge pull request #29 from zenangst/feature/view-injection
Browse files Browse the repository at this point in the history
Adds view injection via swizzling
  • Loading branch information
zenangst committed Aug 28, 2018
2 parents b50d01c + 3e880ab commit 3e701f3
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 2 deletions.
23 changes: 23 additions & 0 deletions README.md
Expand Up @@ -147,6 +147,29 @@ class CustomView: UIView {
}
```

If you enable swizzling when loading the injection bundle, then the initializer for all views will be switch out in
order to evaluate if your view conforms to injection. It does this by checking if the view responds to the `loadView` selector.
This removes the need to manual add injection related code into your views. Note that `loadView` needs `@objc` in order
for injection to properly find and invoke the method when the view gets injected. Views that do not respond to the
selector will be ignored.

```swift
class CustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
loadView()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

@objc func loadView() {
// Your code goes here.
}
}
```

If you feel like this is a lot of code to write for all views that you create, I recommend
creating an Xcode template for creating views.

Expand Down
5 changes: 5 additions & 0 deletions Source/Shared/Injection.swift
Expand Up @@ -57,6 +57,10 @@ public class Injection {
return "\(Injection.resourcePath)/\(Injection.bundle)"
}

static var swizzleViews: Bool = false {
didSet { if swizzleViews { View._swizzleViews() } }
}

static var swizzleViewControllers: Bool = false {
didSet { if swizzleViewControllers { ViewController._swizzleViewControllers() } }
}
Expand Down Expand Up @@ -91,6 +95,7 @@ public class Injection {
#endif

swizzleViewControllers = swizzling
swizzleViews = swizzling
closure?()
return self
}
Expand Down
2 changes: 2 additions & 0 deletions Source/Shared/TypeAlias.swift
@@ -1,7 +1,9 @@
#if os(macOS)
import Cocoa
public typealias ViewController = NSViewController
public typealias View = NSView
#else
import UIKit
public typealias ViewController = UIViewController
public typealias View = UIView
#endif
38 changes: 38 additions & 0 deletions Source/Shared/View+Extensions.swift
@@ -0,0 +1,38 @@
#if os(macOS)
import Cocoa
public typealias Rect = NSRect
#else
import UIKit
public typealias Rect = CGRect
#endif

extension View {
// Swizzle initializers for views if application is compiled in debug mode.
static func _swizzleViews() {
#if DEBUG
DispatchQueue.once(token: "com.zenangst.Vaccine.swizzleViews") {
let originalSelector = #selector(View.init(frame:))
let swizzledSelector = #selector(View.init(vaccineFrame:))
Swizzling.swizzle(View.self,
originalSelector: originalSelector,
swizzledSelector: swizzledSelector)
}
#endif

}

@objc public convenience init(vaccineFrame frame: Rect) {
self.init(vaccineFrame: frame)
let selector = #selector(View.vaccine_view_injected(_:))
if responds(to: selector) {
addInjection(with: selector, invoke: nil)
}
}

@objc func vaccine_view_injected(_ notification: Notification) {
let selector = Selector("loadView")
if responds(to: selector), Injection.objectWasInjected(self, in: notification) {
perform(selector)
}
}
}
2 changes: 1 addition & 1 deletion Vaccine.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "Vaccine"
s.summary = "Make your apps immune to recompile-disease."
s.version = "0.4.4"
s.version = "0.5.0"
s.homepage = "https://github.com/zenangst/Vaccine"
s.license = 'MIT'
s.author = { "Christoffer Winterkvist" => "christoffer@winterkvist.com" }
Expand Down
10 changes: 9 additions & 1 deletion Vaccine.xcodeproj/project.pbxproj
Expand Up @@ -45,6 +45,9 @@
BD7242D120CFC0CB0006DCF7 /* ViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7242CE20CFC0CB0006DCF7 /* ViewController+Extensions.swift */; };
BDEA432620C9216C00CF30A2 /* UIScreen+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDEA432520C9216C00CF30A2 /* UIScreen+Extensions.swift */; };
BDEA432B20C921B600CF30A2 /* Device.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDEA432A20C921B600CF30A2 /* Device.swift */; };
BDFC75882135307B001610EC /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFC75872135307B001610EC /* View+Extensions.swift */; };
BDFC75892135307B001610EC /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFC75872135307B001610EC /* View+Extensions.swift */; };
BDFC758A2135307B001610EC /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFC75872135307B001610EC /* View+Extensions.swift */; };
D284B1051F79038B00D94AF3 /* Vaccine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D284B0FC1F79038B00D94AF3 /* Vaccine.framework */; };
D284B1441F7908B100D94AF3 /* NSObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D284B1321F7906DA00D94AF3 /* NSObjectTests.swift */; };
D284B1451F7908B200D94AF3 /* NSObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D284B1321F7906DA00D94AF3 /* NSObjectTests.swift */; };
Expand Down Expand Up @@ -88,7 +91,7 @@
BD6AC87120B6D5C800CBE8BA /* UIApplicationDelegate+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplicationDelegate+Extensions.swift"; sourceTree = "<group>"; };
BD6AC87420B6D5ED00CBE8BA /* NSApplicationDelegate+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSApplicationDelegate+Extensions.swift"; sourceTree = "<group>"; };
BD6AC87620B6D61B00CBE8BA /* NSObject+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+Extensions.swift"; sourceTree = "<group>"; };
BD6AC87A20B6D65700CBE8BA /* Vaccine.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vaccine.podspec; sourceTree = "<group>"; };
BD6AC87A20B6D65700CBE8BA /* Vaccine.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vaccine.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
BD6AC87B20B6D65700CBE8BA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
BD6F515E20B73A6E001E113B /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
BD6F516220B73CC6001E113B /* ViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerTests.swift; sourceTree = "<group>"; };
Expand All @@ -100,6 +103,7 @@
BD7242CE20CFC0CB0006DCF7 /* ViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewController+Extensions.swift"; sourceTree = "<group>"; };
BDEA432520C9216C00CF30A2 /* UIScreen+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScreen+Extensions.swift"; sourceTree = "<group>"; };
BDEA432A20C921B600CF30A2 /* Device.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Device.swift; sourceTree = "<group>"; };
BDFC75872135307B001610EC /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
D284B0FC1F79038B00D94AF3 /* Vaccine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Vaccine.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D284B1041F79038B00D94AF3 /* Vaccine-tvOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Vaccine-tvOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D284B12E1F7906DA00D94AF3 /* NSApplicationDelegateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSApplicationDelegateTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -299,6 +303,7 @@
BD6AC87620B6D61B00CBE8BA /* NSObject+Extensions.swift */,
BD7242C620CFBE760006DCF7 /* Swizzling.swift */,
BD4B8C4920C860CB00836815 /* TypeAlias.swift */,
BDFC75872135307B001610EC /* View+Extensions.swift */,
BD7242CE20CFC0CB0006DCF7 /* ViewController+Extensions.swift */,
);
path = Shared;
Expand Down Expand Up @@ -563,6 +568,7 @@
buildActionMask = 2147483647;
files = (
BD6F516D20B7D6BA001E113B /* Injection.swift in Sources */,
BDFC758A2135307B001610EC /* View+Extensions.swift in Sources */,
BD7242C920CFBE760006DCF7 /* Swizzling.swift in Sources */,
BD6AC87320B6D5C800CBE8BA /* UIApplicationDelegate+Extensions.swift in Sources */,
BD5FC7F420B80D8500A08D21 /* UIViewController+Extensions.swift in Sources */,
Expand Down Expand Up @@ -591,6 +597,7 @@
files = (
BD6F516B20B7D6BA001E113B /* Injection.swift in Sources */,
BDEA432620C9216C00CF30A2 /* UIScreen+Extensions.swift in Sources */,
BDFC75882135307B001610EC /* View+Extensions.swift in Sources */,
BD6AC87220B6D5C800CBE8BA /* UIApplicationDelegate+Extensions.swift in Sources */,
BD7242C720CFBE760006DCF7 /* Swizzling.swift in Sources */,
BD5FC7F320B80D8500A08D21 /* UIViewController+Extensions.swift in Sources */,
Expand Down Expand Up @@ -621,6 +628,7 @@
buildActionMask = 2147483647;
files = (
BD6F516C20B7D6BA001E113B /* Injection.swift in Sources */,
BDFC75892135307B001610EC /* View+Extensions.swift in Sources */,
BD7242C820CFBE760006DCF7 /* Swizzling.swift in Sources */,
BD592EB820B837BB006DE955 /* NSViewController+Extensions.swift in Sources */,
BD6AC87520B6D5ED00CBE8BA /* NSApplicationDelegate+Extensions.swift in Sources */,
Expand Down

0 comments on commit 3e701f3

Please sign in to comment.