Skip to content

Commit

Permalink
Properly prevent duplicit view controller injection
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubvano committed Oct 28, 2016
1 parent 83d3aa5 commit 2159604
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 44 deletions.
11 changes: 11 additions & 0 deletions Sources/InjectionVerifiable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// InjectionVerifiable.swift
// Swinject
//
// Created by Jakub Vaňo on 28/10/16.
// Copyright © 2016 Swinject Contributors. All rights reserved.
//

internal protocol InjectionVerifiable: AnyObject {
var wasInjected: Bool { get set }
}
13 changes: 0 additions & 13 deletions Sources/RegistrationNameAssociatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,6 @@
// Copyright © 2015 Swinject Contributors. All rights reserved.
//

import Foundation
import ObjectiveC

internal protocol RegistrationNameAssociatable: AnyObject {
var swinjectRegistrationName: String? { get set }
}

extension RegistrationNameAssociatable {
internal func getAssociatedString(key: UnsafeRawPointer) -> String? {
return objc_getAssociatedObject(self, key) as? String
}

internal func setAssociatedString(_ string: String?, key: UnsafeRawPointer) {
objc_setAssociatedObject(self, key, string, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
}
}
18 changes: 12 additions & 6 deletions Sources/SwinjectStoryboard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,15 @@ public class SwinjectStoryboard: _SwinjectStoryboardBase, SwinjectStoryboardType
let viewController = super.instantiateViewController(withIdentifier: identifier)
SwinjectStoryboard.popInstantiatingStoryboard()

if !SwinjectStoryboard.isCreatingStoryboardReference {
injectDependency(to: viewController)
}
injectDependency(to: viewController)

return viewController
}

private func injectDependency(to viewController: UIViewController) {
guard !viewController.wasInjected else { return }
defer { viewController.wasInjected = true }

let registrationName = viewController.swinjectRegistrationName

// Xcode 7.1 workaround for Issue #10. This workaround is not necessary with Xcode 7.
Expand Down Expand Up @@ -120,13 +122,17 @@ public class SwinjectStoryboard: _SwinjectStoryboardBase, SwinjectStoryboardType
let controller = super.instantiateController(withIdentifier: identifier)
SwinjectStoryboard.popInstantiatingStoryboard()

if !SwinjectStoryboard.isCreatingStoryboardReference {
injectDependency(to: controller)
}
injectDependency(to: controller)

return controller
}

private func injectDependency(to controller: Container.Controller) {
if let controller = controller as? InjectionVerifiable {
guard !controller.wasInjected else { return }
defer { controller.wasInjected = true }
}

let registrationName = (controller as? RegistrationNameAssociatable)?.swinjectRegistrationName

// Xcode 7.1 workaround for Issue #10. This workaround is not necessary with Xcode 7.
Expand Down
74 changes: 49 additions & 25 deletions Sources/ViewController+Swinject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,72 @@
// Copyright © 2015 Swinject Contributors. All rights reserved.
//

import Swinject
import ObjectiveC

#if os(iOS) || os(tvOS)

private var uivcAssociationKey: String = "UIViewController.swinjectRegistrationName"
private var uivcRegistrationNameKey: String = "UIViewController.swinjectRegistrationName"
private var uivcWasInjectedKey: String = "UIViewController.wasInjected"

extension UIViewController: RegistrationNameAssociatable {
extension UIViewController: RegistrationNameAssociatable, InjectionVerifiable {
internal var swinjectRegistrationName: String? {
get {
return getAssociatedString(key: &uivcAssociationKey)
}
set {
setAssociatedString(newValue, key: &uivcAssociationKey)
}
get { return getAssociatedString(key: &uivcRegistrationNameKey) }
set { setAssociatedString(newValue, key: &uivcRegistrationNameKey) }
}

internal var wasInjected: Bool {
get { return getAssociatedBool(key: &uivcWasInjectedKey) ?? false }
set { setAssociatedBool(newValue, key: &uivcWasInjectedKey) }
}
}

#elseif os(OSX)

private var nsvcAssociationKey: String = "NSViewController.swinjectRegistrationName"
private var nswcAssociationKey: String = "NSWindowController.swinjectRegistrationName"
private var nsvcRegistrationNameKey: String = "NSViewController.swinjectRegistrationName"
private var nswcRegistrationNameKey: String = "NSWindowController.swinjectRegistrationName"
private var nsvcWasInjectedKey: String = "NSViewController.wasInjected"
private var nswcWasInjectedKey: String = "NSWindowController.wasInjected"

extension NSViewController: RegistrationNameAssociatable {
extension NSViewController: RegistrationNameAssociatable, InjectionVerifiable {
internal var swinjectRegistrationName: String? {
get {
return getAssociatedString(key: &nsvcAssociationKey)
}
set {
setAssociatedString(newValue, key: &nsvcAssociationKey)
}
get { return getAssociatedString(key: &nsvcRegistrationNameKey) }
set { setAssociatedString(newValue, key: &nsvcRegistrationNameKey) }
}

internal var wasInjected: Bool {
get { return getAssociatedBool(key: &nsvcWasInjectedKey) ?? false }
set { setAssociatedBool(newValue, key: &nsvcWasInjectedKey) }
}
}

extension NSWindowController: RegistrationNameAssociatable {
extension NSWindowController: RegistrationNameAssociatable, InjectionVerifiable {
internal var swinjectRegistrationName: String? {
get {
return getAssociatedString(key: &nswcAssociationKey)
}
set {
setAssociatedString(newValue, key: &nswcAssociationKey)
}
get { return getAssociatedString(key: &nsvcRegistrationNameKey) }
set { setAssociatedString(newValue, key: &nsvcRegistrationNameKey) }
}

internal var wasInjected: Bool {
get { return getAssociatedBool(key: &nswcWasInjectedKey) ?? false }
set { setAssociatedBool(newValue, key: &nswcWasInjectedKey) }
}
}

#endif

extension NSObject {
fileprivate func getAssociatedString(key: UnsafeRawPointer) -> String? {
return objc_getAssociatedObject(self, key) as? String
}

fileprivate func setAssociatedString(_ string: String?, key: UnsafeRawPointer) {
objc_setAssociatedObject(self, key, string, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
}

fileprivate func getAssociatedBool(key: UnsafeRawPointer) -> Bool? {
return (objc_getAssociatedObject(self, key) as? NSNumber)?.boolValue
}

fileprivate func setAssociatedBool(_ bool: Bool, key: UnsafeRawPointer) {
objc_setAssociatedObject(self, key, NSNumber(value: bool), objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
}
}
8 changes: 8 additions & 0 deletions SwinjectStoryboard.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
CD3AB1AA1DC3A858001A45FA /* Pages.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD3AB1A81DC3A858001A45FA /* Pages.storyboard */; };
CD3AB1AE1DC3A8CD001A45FA /* AnimalPagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD3AB1AD1DC3A8CD001A45FA /* AnimalPagesViewController.swift */; };
CD3AB1B01DC3A8D6001A45FA /* Pages.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD3AB1AF1DC3A8D6001A45FA /* Pages.storyboard */; };
CD3AB1B21DC3A94A001A45FA /* InjectionVerifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD3AB1B11DC3A94A001A45FA /* InjectionVerifiable.swift */; };
CD3AB1B31DC3A94A001A45FA /* InjectionVerifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD3AB1B11DC3A94A001A45FA /* InjectionVerifiable.swift */; };
CD3AB1B41DC3A94A001A45FA /* InjectionVerifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD3AB1B11DC3A94A001A45FA /* InjectionVerifiable.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -433,6 +436,7 @@
CD3AB1A81DC3A858001A45FA /* Pages.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Pages.storyboard; sourceTree = "<group>"; };
CD3AB1AD1DC3A8CD001A45FA /* AnimalPagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimalPagesViewController.swift; sourceTree = "<group>"; };
CD3AB1AF1DC3A8D6001A45FA /* Pages.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Pages.storyboard; sourceTree = "<group>"; };
CD3AB1B11DC3A94A001A45FA /* InjectionVerifiable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InjectionVerifiable.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -626,6 +630,7 @@
983DFEA01CDB410D00D39731 /* Storyboard+Swizzling.swift */,
983DFEA41CDB410D00D39731 /* ViewController+Swinject.swift */,
983DFF0A1CDB440800D39731 /* Box.swift */,
CD3AB1B11DC3A94A001A45FA /* InjectionVerifiable.swift */,
983DFF0E1CDB444E00D39731 /* RegistrationNameAssociatable.swift */,
CD2C63A91D7864840075BC14 /* SwinjectStoryboard+StoryboardReference.swift */,
985904091CDB0AA700275E4A /* SwinjectStoryboard.h */,
Expand Down Expand Up @@ -1208,6 +1213,7 @@
files = (
983DFEA81CDB410D00D39731 /* Storyboard+Swizzling.swift in Sources */,
983DFEA51CDB410D00D39731 /* Container+SwinjectStoryboard.swift in Sources */,
CD3AB1B21DC3A94A001A45FA /* InjectionVerifiable.swift in Sources */,
983DFEAE1CDB410D00D39731 /* SwinjectStoryboardOption.swift in Sources */,
983DFF0F1CDB444E00D39731 /* RegistrationNameAssociatable.swift in Sources */,
983DFEAB1CDB410D00D39731 /* SwinjectStoryboard.swift in Sources */,
Expand Down Expand Up @@ -1243,6 +1249,7 @@
files = (
983DFEA91CDB410D00D39731 /* Storyboard+Swizzling.swift in Sources */,
983DFEA61CDB410D00D39731 /* Container+SwinjectStoryboard.swift in Sources */,
CD3AB1B31DC3A94A001A45FA /* InjectionVerifiable.swift in Sources */,
983DFEAF1CDB410D00D39731 /* SwinjectStoryboardOption.swift in Sources */,
983DFF101CDB444E00D39731 /* RegistrationNameAssociatable.swift in Sources */,
CD2C63B01D786D6B0075BC14 /* SwinjectStoryboard+StoryboardReference.swift in Sources */,
Expand Down Expand Up @@ -1279,6 +1286,7 @@
files = (
983DFEAA1CDB410D00D39731 /* Storyboard+Swizzling.swift in Sources */,
983DFEA71CDB410D00D39731 /* Container+SwinjectStoryboard.swift in Sources */,
CD3AB1B41DC3A94A001A45FA /* InjectionVerifiable.swift in Sources */,
983DFEB01CDB410D00D39731 /* SwinjectStoryboardOption.swift in Sources */,
983DFF111CDB444E00D39731 /* RegistrationNameAssociatable.swift in Sources */,
983DFEAD1CDB410D00D39731 /* SwinjectStoryboard.swift in Sources */,
Expand Down

0 comments on commit 2159604

Please sign in to comment.