├── .gitignore
├── .gitmodules
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── .travis.yml
├── Assets
├── AnimalViewControllerScreenshot1.png
└── AnimalViewControllerScreenshot2.png
├── Cartfile
├── Cartfile.resolved
├── Configurations
├── Base
│ ├── Common.xcconfig
│ ├── Configurations
│ │ ├── Debug.xcconfig
│ │ ├── Profile.xcconfig
│ │ ├── Release.xcconfig
│ │ └── Test.xcconfig
│ └── Targets
│ │ ├── Application.xcconfig
│ │ ├── Framework.xcconfig
│ │ └── StaticLibrary.xcconfig
├── Mac OS X
│ ├── Mac-Application.xcconfig
│ ├── Mac-Base.xcconfig
│ ├── Mac-DynamicLibrary.xcconfig
│ ├── Mac-Framework.xcconfig
│ └── Mac-StaticLibrary.xcconfig
├── iOS
│ ├── iOS-Application.xcconfig
│ ├── iOS-Base.xcconfig
│ ├── iOS-Framework.xcconfig
│ └── iOS-StaticLibrary.xcconfig
├── tvOS
│ ├── tvOS-Application.xcconfig
│ ├── tvOS-Base.xcconfig
│ ├── tvOS-Framework.xcconfig
│ └── tvOS-StaticLibrary.xcconfig
└── watchOS
│ ├── watchOS-Application.xcconfig
│ ├── watchOS-Base.xcconfig
│ ├── watchOS-Framework.xcconfig
│ └── watchOS-StaticLibrary.xcconfig
├── Gemfile
├── Gemfile.lock
├── LICENSE.txt
├── Makefile
├── Package.resolved
├── Package.swift
├── README.md
├── Sources
├── Box.swift
├── Container+SwinjectStoryboard.swift
├── DispatchQueue+Once.swift
├── Info.plist
├── InjectionVerifiable.swift
├── OSX
│ ├── NSStoryboard+Swizzling.swift
│ └── _SwinjectStoryboardBase(OSX).swift
├── ObjectiveC
│ └── Others
│ │ └── SwinjectStoryboard+SetUp.m
├── RegistrationNameAssociatable.swift
├── SwinjectStoryboard+StoryboardReference.swift
├── SwinjectStoryboard.swift
├── SwinjectStoryboardOption.swift
├── SwinjectStoryboardProtocol.swift
├── UnavailableItems.swift
├── ViewController+Swinject.swift
└── iOS-tvOS
│ ├── UIStoryboard+Swizzling.swift
│ └── _SwinjectStoryboardBase(iOS-tvOS).swift
├── SwinjectStoryboard.podspec
├── SwinjectStoryboard.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ ├── SwinjectStoryboard-OSX.xcscheme
│ ├── SwinjectStoryboard-iOS.xcscheme
│ └── SwinjectStoryboard-tvOS.xcscheme
├── Tests
├── Animal.swift
├── Container+SwinjectStoryboardTests.swift
├── Food.swift
├── Info.plist
├── NSWindowController+SwinjectTests.swift
├── OSX
│ ├── AnimalPagesViewController.swift
│ ├── AnimalViewController.swift
│ ├── AnimalWindowController.swift
│ ├── Animals.storyboard
│ ├── Pages.storyboard
│ ├── RelationshipReference1.storyboard
│ ├── RelationshipReference2.storyboard
│ ├── Storyboard1.storyboard
│ ├── Storyboard2.storyboard
│ ├── SwinjectStoryboardTests.swift
│ ├── Tabs.storyboard
│ └── ViewController1.swift
├── Storyboard+SwizzlingTests.swift
├── ViewController+SwinjectTests.swift
└── iOS-tvOS
│ ├── AnimalPagesViewController.swift
│ ├── AnimalPlayerViewController.swift
│ ├── AnimalViewController.swift
│ ├── Storyboards
│ ├── iOS
│ │ ├── AnimalPlayerViewController.storyboard
│ │ ├── Animals.storyboard
│ │ ├── Pages.storyboard
│ │ ├── RelationshipReference1.storyboard
│ │ ├── RelationshipReference2.storyboard
│ │ ├── Storyboard1.storyboard
│ │ ├── Storyboard2.storyboard
│ │ └── Tabs.storyboard
│ └── tvOS
│ │ ├── AnimalPlayerViewController.storyboard
│ │ ├── Animals.storyboard
│ │ ├── Pages.storyboard
│ │ ├── RelationshipReference1.storyboard
│ │ ├── RelationshipReference2.storyboard
│ │ ├── Storyboard1.storyboard
│ │ ├── Storyboard2.storyboard
│ │ └── Tabs.storyboard
│ └── SwinjectStoryboardTests.swift
└── carthage-build.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | #
2 | # https://github.com/github/gitignore/blob/master/Swift.gitignore
3 | #
4 |
5 | ## Build generated
6 | build/
7 | DerivedData
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata
19 |
20 | ## Other
21 | *.xccheckout
22 | *.moved-aside
23 | *.xcuserstate
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | # Pods/
47 |
48 | # Carthage
49 | #
50 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
51 | Carthage/Checkouts
52 | Carthage/Build
53 |
54 | # fastlane
55 | #
56 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
57 | # screenshots whenever they are needed.
58 | # For more information about the recommended setup visit:
59 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
60 |
61 | fastlane/report.xml
62 | fastlane/screenshots
63 |
64 | ## Mac
65 | .DS_Store
66 |
67 | ## SwinjectStoryboard
68 | SwinjectStoryboard.framework.zip
69 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # reference: http://www.objc.io/issue-6/travis-ci.html
2 |
3 | language: objective-c
4 | osx_image: xcode11
5 | env:
6 | global:
7 | - LC_CTYPE=en_US.UTF-8
8 | - LANG=en_US.UTF-8
9 | - PROJECT=SwinjectStoryboard.xcodeproj
10 | matrix:
11 | include:
12 | - env: JOB="POD_LINT"
13 | osx_image: xcode11
14 | script:
15 | - bundle exec pod repo update
16 | - bundle exec pod lib lint
17 | - env: JOB="XCODE" DEST="OS=10.3.1,name=iPhone 6" SCHEME="SwinjectStoryboard-iOS" SDK="iphonesimulator" ACTION="test"
18 | osx_image: xcode11
19 | - env: JOB="XCODE" DEST="OS=11.0.1,name=iPhone 7 Plus" SCHEME="SwinjectStoryboard-iOS" SDK="iphonesimulator" ACTION="test"
20 | osx_image: xcode11
21 | - env: JOB="XCODE" DEST="OS=11.2,name=iPhone 8 Plus" SCHEME="SwinjectStoryboard-iOS" SDK="iphonesimulator" ACTION="test"
22 | osx_image: xcode11
23 | - env: JOB="XCODE" DEST="OS=12.2,name=iPhone X" SCHEME="SwinjectStoryboard-iOS" SDK="iphonesimulator" ACTION="test"
24 | osx_image: xcode11
25 | - env: JOB="XCODE" DEST="OS=13.0,name=iPhone 11 Pro" SCHEME="SwinjectStoryboard-iOS" SDK="iphonesimulator" ACTION="test"
26 | osx_image: xcode11
27 | - env: JOB="XCODE" DEST="arch=x86_64" SCHEME="SwinjectStoryboard-OSX" SDK="macosx" ACTION="test"
28 | osx_image: xcode11
29 | - env: JOB="XCODE" DEST="arch=x86_64" SCHEME="SwinjectStoryboard-OSX" SDK="macosx" ACTION="test"
30 | osx_image: xcode11
31 | - env: JOB="XCODE" DEST="OS=10.2,name=Apple TV 1080p" SCHEME="SwinjectStoryboard-tvOS" SDK="appletvsimulator" ACTION="test"
32 | osx_image: xcode11
33 | - env: JOB="XCODE" DEST="OS=11.0,name=Apple TV 1080p" SCHEME="SwinjectStoryboard-tvOS" SDK="appletvsimulator" ACTION="test"
34 | osx_image: xcode11
35 | - env: JOB="XCODE" DEST="OS=13.0,name=Apple TV 4K" SCHEME="SwinjectStoryboard-tvOS" SDK="appletvsimulator" ACTION="test"
36 | osx_image: xcode11
37 | before_install:
38 | - curl -L -O https://github.com/Carthage/Carthage/releases/download/0.33.0/Carthage.pkg
39 | - sudo installer -pkg Carthage.pkg -target /
40 | - rm Carthage.pkg
41 | - carthage bootstrap --platform iOS,macOS,tvOS --cache-builds
42 | script:
43 | - set -o pipefail
44 | - xcodebuild "$ACTION" -project "$PROJECT" -scheme "$SCHEME" -sdk "$SDK" -destination "$DEST" -configuration Release ENABLE_TESTABILITY=YES | xcpretty
45 | notifications:
46 | email:
47 | on_success: never
48 |
49 | cache:
50 | directories:
51 | - Carthage
52 |
--------------------------------------------------------------------------------
/Assets/AnimalViewControllerScreenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Swinject/SwinjectStoryboard/7a446cc8d8880a403519a4a43e1b64c086dd265c/Assets/AnimalViewControllerScreenshot1.png
--------------------------------------------------------------------------------
/Assets/AnimalViewControllerScreenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Swinject/SwinjectStoryboard/7a446cc8d8880a403519a4a43e1b64c086dd265c/Assets/AnimalViewControllerScreenshot2.png
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "Swinject/Swinject" ~> 2.7.1
2 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "Swinject/Swinject" "2.7.1"
2 |
--------------------------------------------------------------------------------
/Configurations/Base/Common.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines common settings that should be enabled for every new
3 | // project. Typically, you want to use Debug, Release, or a similar variant
4 | // instead.
5 | //
6 |
7 | // Disable legacy-compatible header searching
8 | ALWAYS_SEARCH_USER_PATHS = NO
9 |
10 | // Architectures to build
11 | ARCHS = $(ARCHS_STANDARD)
12 |
13 | // Whether to warn when a floating-point value is used as a loop counter
14 | CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
15 |
16 | // Whether to warn about use of rand() and random() being used instead of arc4random()
17 | CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
18 |
19 | // Whether to warn about strcpy() and strcat()
20 | CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES
21 |
22 | // Whether to enable module imports
23 | CLANG_ENABLE_MODULES = YES
24 |
25 | // Enable ARC
26 | CLANG_ENABLE_OBJC_ARC = YES
27 |
28 | // Warn about block captures of implicitly autoreleasing parameters.
29 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
30 |
31 | // Warn about implicit conversions to boolean values that are suspicious.
32 | // For example, writing 'if (foo)' with 'foo' being the name a function will trigger a warning.
33 | CLANG_WARN_BOOL_CONVERSION = YES
34 |
35 | // Warn about suspicious uses of the comma operator.
36 | CLANG_WARN_COMMA = YES
37 |
38 | // Warn about implicit conversions of constant values that cause the constant value to change,
39 | // either through a loss of precision, or entirely in its meaning.
40 | CLANG_WARN_CONSTANT_CONVERSION = YES
41 |
42 | // Whether to warn when overriding deprecated methods
43 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
44 |
45 | // Warn about direct accesses to the Objective-C 'isa' pointer instead of using a runtime API.
46 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
47 |
48 | // Warn about declaring the same method more than once within the same @interface.
49 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
50 |
51 | // Warn about loop bodies that are suspiciously empty.
52 | CLANG_WARN_EMPTY_BODY = YES
53 |
54 | // Warn about implicit conversions between different kinds of enum values.
55 | // For example, this can catch issues when using the wrong enum flag as an argument to a function or method.
56 | CLANG_WARN_ENUM_CONVERSION = YES
57 |
58 | // Whether to warn on implicit conversions between signed/unsigned types
59 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
60 |
61 | // Warn about implicit conversions between pointers and integers.
62 | // For example, this can catch issues when one incorrectly intermixes using NSNumbers and raw integers.
63 | CLANG_WARN_INT_CONVERSION = YES
64 |
65 | // Warn about non-literal expressions that evaluate to zero being treated as a null pointer.
66 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
67 |
68 | // Warn about implicit capture of self (e.g. direct ivar access)
69 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
70 |
71 | // Warn about implicit conversions from Objective-C literals to values of incompatible type.
72 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
73 |
74 | // Don't warn about repeatedly using a weak reference without assigning the weak reference to a strong reference. Too many false positives.
75 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO
76 |
77 | // Warn about classes that unintentionally do not subclass a root class (such as NSObject).
78 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
79 |
80 | // Warn about ranged-based for loops.
81 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
82 |
83 | // Whether to warn on suspicious implicit conversions
84 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
85 |
86 | // Warn about non-prototype declarations.
87 | CLANG_WARN_STRICT_PROTOTYPES = YES
88 |
89 | // Warn if an API that is newer than the deployment target is used without "if (@available(...))" guards.
90 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES
91 |
92 | // Warn about incorrect uses of nullable values
93 | CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES
94 |
95 | // Warn for missing nullability attributes
96 | CLANG_ANALYZER_NONNULL = YES
97 |
98 | // Warn when a non-localized string is passed to a user-interface method expecting a localized string
99 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES
100 |
101 | // Warn about potentially unreachable code
102 | CLANG_WARN_UNREACHABLE_CODE = YES
103 |
104 | // The format of debugging symbols
105 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
106 |
107 | // Whether to compile assertions in
108 | ENABLE_NS_ASSERTIONS = YES
109 |
110 | // Whether to require objc_msgSend to be cast before invocation
111 | ENABLE_STRICT_OBJC_MSGSEND = YES
112 |
113 | // Which C variant to use
114 | GCC_C_LANGUAGE_STANDARD = gnu99
115 |
116 | // Whether to enable exceptions for Objective-C
117 | GCC_ENABLE_OBJC_EXCEPTIONS = YES
118 |
119 | // Whether to generate debugging symbols
120 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES
121 |
122 | // Whether to precompile the prefix header (if one is specified)
123 | GCC_PRECOMPILE_PREFIX_HEADER = YES
124 |
125 | // Whether to enable strict aliasing, meaning that two pointers of different
126 | // types (other than void * or any id type) cannot point to the same memory
127 | // location
128 | GCC_STRICT_ALIASING = YES
129 |
130 | // Whether symbols not explicitly exported are hidden by default (this primarily
131 | // only affects C++ code)
132 | GCC_SYMBOLS_PRIVATE_EXTERN = NO
133 |
134 | // Whether static variables are thread-safe by default
135 | GCC_THREADSAFE_STATICS = NO
136 |
137 | // Which compiler to use
138 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0
139 |
140 | // Whether warnings are treated as errors
141 | GCC_TREAT_WARNINGS_AS_ERRORS = YES
142 | SWIFT_TREAT_WARNINGS_AS_ERRORS = YES
143 |
144 | // Whether to warn about 64-bit values being implicitly shortened to 32 bits
145 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES
146 |
147 | // Whether to warn about fields missing from structure initializers (only if
148 | // designated initializers aren't used)
149 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
150 |
151 | // Whether to warn about missing function prototypes
152 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO
153 |
154 | // Whether to warn about implicit conversions in the signedness of the type
155 | // a pointer is pointing to (e.g., 'int *' getting converted to 'unsigned int *')
156 | GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
157 |
158 | // Whether to warn when the value returned from a function/method/block does not
159 | // match its return type
160 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
161 |
162 | // Whether to warn on a class not implementing all the required methods of
163 | // a protocol it declares conformance to
164 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES
165 |
166 | // Whether to warn when switching on an enum value, and all possibilities are
167 | // not accounted for
168 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
169 |
170 | // Whether to warn about the use of four-character constants
171 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
172 |
173 | // Whether to warn about an aggregate data type's initializer not being fully
174 | // bracketed (e.g., array initializer syntax)
175 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
176 |
177 | // Whether to warn about missing braces or parentheses that make the meaning of
178 | // the code ambiguous
179 | GCC_WARN_MISSING_PARENTHESES = YES
180 |
181 | // Whether to warn about unsafe comparisons between values of different
182 | // signedness
183 | GCC_WARN_SIGN_COMPARE = YES
184 |
185 | // Whether to warn about the arguments to printf-style functions not matching
186 | // the format specifiers
187 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
188 |
189 | // Warn if a "@selector(...)" expression referring to an undeclared selector is found
190 | GCC_WARN_UNDECLARED_SELECTOR = YES
191 |
192 | // Warn if a variable might be clobbered by a setjmp call or if an automatic variable is used without prior initialization.
193 | GCC_WARN_UNINITIALIZED_AUTOS = YES
194 |
195 | // Whether to warn about static functions that are unused
196 | GCC_WARN_UNUSED_FUNCTION = YES
197 |
198 | // Whether to warn about labels that are unused
199 | GCC_WARN_UNUSED_LABEL = YES
200 |
201 | // Whether to warn about variables that are never used
202 | GCC_WARN_UNUSED_VARIABLE = YES
203 |
204 | // Whether to run the static analyzer with every build
205 | RUN_CLANG_STATIC_ANALYZER = YES
206 |
207 | // Don't treat unknown warnings as errors, and disable GCC compatibility warnings and unused static const variable warnings
208 | WARNING_CFLAGS = -Wno-error=unknown-warning-option -Wno-gcc-compat -Wno-unused-const-variable
209 |
210 | // This setting is on for new projects as of Xcode ~6.3, though it is still not
211 | // the default. It warns if the same variable is declared in two binaries that
212 | // are linked together.
213 | GCC_NO_COMMON_BLOCKS = YES
214 |
215 | // This warnings detects when a function will recursively call itself on every
216 | // code path though that function. More information can be found here:
217 | // http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20131216/096004.html
218 | CLANG_WARN_INFINITE_RECURSION = YES
219 |
220 | // This warning detects suspicious uses of std::move.
221 | CLANG_WARN_SUSPICIOUS_MOVE = YES
222 |
--------------------------------------------------------------------------------
/Configurations/Base/Configurations/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines the base configuration for a Debug build of any project.
3 | // This should be set at the project level for the Debug configuration.
4 | //
5 |
6 | #include "../Common.xcconfig"
7 |
8 | // Whether to strip debugging symbols when copying resources (like included
9 | // binaries)
10 | COPY_PHASE_STRIP = NO
11 |
12 | // The optimization level (0, 1, 2, 3, s) for the produced binary
13 | GCC_OPTIMIZATION_LEVEL = 0
14 |
15 | // Preproccessor definitions to apply to each file compiled
16 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1
17 |
18 | // Allow @testable imports
19 | ENABLE_TESTABILITY = YES
20 |
21 | // Whether to enable link-time optimizations (such as inlining across translation
22 | // units)
23 | LLVM_LTO = NO
24 |
25 | // Whether to only build the active architecture
26 | ONLY_ACTIVE_ARCH = YES
27 |
28 | // Other compiler flags
29 | //
30 | // These settings catch some errors in integer arithmetic
31 | OTHER_CFLAGS = -ftrapv
32 |
33 | // Other flags to pass to the Swift compiler
34 | //
35 | // This enables conditional compilation with #if DEBUG
36 | OTHER_SWIFT_FLAGS = -D DEBUG
37 |
38 | // Xcode 8 introduced a new flag for conditional compilation
39 | //
40 | // This enables conditional compilation with #if DEBUG
41 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG
42 |
43 | // Whether to strip debugging symbols when copying the built product to its
44 | // final installation location
45 | STRIP_INSTALLED_PRODUCT = NO
46 |
47 | // The optimization level (-Onone, -O, -Ofast) for the produced Swift binary
48 | SWIFT_OPTIMIZATION_LEVEL = -Onone
49 |
50 | // Disable Developer ID timestamping
51 | OTHER_CODE_SIGN_FLAGS = --timestamp=none
52 |
--------------------------------------------------------------------------------
/Configurations/Base/Configurations/Profile.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines the base configuration for an optional profiling-specific
3 | // build of any project. To use these settings, create a Profile configuration
4 | // in your project, and use this file at the project level for the new
5 | // configuration.
6 | //
7 |
8 | // based on the Release configuration, with some stuff related to debugging
9 | // symbols re-enabled
10 | #include "Release.xcconfig"
11 |
12 | // Whether to strip debugging symbols when copying resources (like included
13 | // binaries)
14 | COPY_PHASE_STRIP = NO
15 |
16 | // Whether to only build the active architecture
17 | ONLY_ACTIVE_ARCH = YES
18 |
19 | // Whether to strip debugging symbols when copying the built product to its
20 | // final installation location
21 | STRIP_INSTALLED_PRODUCT = NO
22 |
23 | // Whether to perform App Store validation checks
24 | VALIDATE_PRODUCT = NO
25 |
26 | // Disable Developer ID timestamping
27 | OTHER_CODE_SIGN_FLAGS = --timestamp=none
28 |
--------------------------------------------------------------------------------
/Configurations/Base/Configurations/Release.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines the base configuration for a Release build of any project.
3 | // This should be set at the project level for the Release configuration.
4 | //
5 |
6 | #include "../Common.xcconfig"
7 |
8 | // Whether to strip debugging symbols when copying resources (like included
9 | // binaries)
10 | COPY_PHASE_STRIP = YES
11 |
12 | // The optimization level (0, 1, 2, 3, s) for the produced binary
13 | GCC_OPTIMIZATION_LEVEL = s
14 |
15 | // Preproccessor definitions to apply to each file compiled
16 | GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1
17 |
18 | // Whether to enable link-time optimizations (such as inlining across translation
19 | // units)
20 | LLVM_LTO = NO
21 |
22 | // Whether to only build the active architecture
23 | ONLY_ACTIVE_ARCH = NO
24 |
25 | // Whether to strip debugging symbols when copying the built product to its
26 | // final installation location
27 | STRIP_INSTALLED_PRODUCT = YES
28 |
29 | // The optimization level (-Onone, -O, -Owholemodule) for the produced Swift binary
30 | SWIFT_OPTIMIZATION_LEVEL = -Owholemodule
31 |
32 | // Whether to perform App Store validation checks
33 | VALIDATE_PRODUCT = YES
34 |
35 |
--------------------------------------------------------------------------------
/Configurations/Base/Configurations/Test.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines the base configuration for a Test build of any project.
3 | // This should be set at the project level for the Test configuration.
4 | //
5 |
6 | #include "Debug.xcconfig"
7 |
8 | // Sandboxed apps can't be unit tested since they can't load some random
9 | // external bundle. So we disable sandboxing for testing.
10 | CODE_SIGN_ENTITLEMENTS =
11 |
12 | // Allow @testable imports
13 | ENABLE_TESTABILITY = YES
14 |
--------------------------------------------------------------------------------
/Configurations/Base/Targets/Application.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for an application. Typically, you want to use a platform-specific variant
4 | // instead.
5 | //
6 |
7 | // Whether to strip out code that isn't called from anywhere
8 | DEAD_CODE_STRIPPING = NO
9 |
10 | // Sets the @rpath for the application such that it can include frameworks in
11 | // the application bundle (inside the "Frameworks" folder)
12 | LD_RUNPATH_SEARCH_PATHS = @executable_path/../Frameworks @loader_path/../Frameworks @executable_path/Frameworks
13 |
--------------------------------------------------------------------------------
/Configurations/Base/Targets/Framework.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a framework. Typically, you want to use a platform-specific variant
4 | // instead.
5 | //
6 |
7 | // Disable code signing for successful device builds with Xcode 8. Frameworks do
8 | // need to be signed, but they don't need to be signed at compile time because
9 | // they'll be re-signed when you include them in your app.
10 | CODE_SIGNING_REQUIRED = NO
11 | CODE_SIGN_IDENTITY =
12 |
13 | // Whether to strip out code that isn't called from anywhere
14 | DEAD_CODE_STRIPPING = NO
15 |
16 | // Whether this framework should define an LLVM module
17 | DEFINES_MODULE = YES
18 |
19 | // Whether function calls should be position-dependent (should always be
20 | // disabled for library code)
21 | GCC_DYNAMIC_NO_PIC = NO
22 |
23 | // Default frameworks to the name of the project, instead of any
24 | // platform-specific target
25 | PRODUCT_NAME = $(PROJECT_NAME)
26 |
27 | // Enables the framework to be included from any location as long as the
28 | // loader’s runpath search paths includes it. For example from an application
29 | // bundle (inside the "Frameworks" folder) or shared folder
30 | INSTALL_PATH = @rpath
31 | LD_DYLIB_INSTALL_NAME = @rpath/$(PRODUCT_NAME).$(WRAPPER_EXTENSION)/$(PRODUCT_NAME)
32 | SKIP_INSTALL = YES
33 |
34 | // Disallows use of APIs that are not available
35 | // to app extensions and linking to frameworks
36 | // that have not been built with this setting enabled.
37 | APPLICATION_EXTENSION_API_ONLY = YES
38 |
--------------------------------------------------------------------------------
/Configurations/Base/Targets/StaticLibrary.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a static library. Typically, you want to use a platform-specific variant
4 | // instead.
5 | //
6 |
7 | // Whether to strip out code that isn't called from anywhere
8 | DEAD_CODE_STRIPPING = NO
9 |
10 | // Whether to strip debugging symbols when copying resources (like included
11 | // binaries).
12 | //
13 | // Overrides Release.xcconfig when used at the target level.
14 | COPY_PHASE_STRIP = NO
15 |
16 | // Whether function calls should be position-dependent (should always be
17 | // disabled for library code)
18 | GCC_DYNAMIC_NO_PIC = NO
19 |
20 | // Copy headers to "include/LibraryName" in the build folder by default. This
21 | // lets consumers use #import syntax even for static
22 | // libraries
23 | PUBLIC_HEADERS_FOLDER_PATH = include/$PRODUCT_NAME
24 |
25 | // Don't include in an xcarchive
26 | SKIP_INSTALL = YES
27 |
28 | // Disallows use of APIs that are not available
29 | // to app extensions and linking to frameworks
30 | // that have not been built with this setting enabled.
31 | APPLICATION_EXTENSION_API_ONLY = YES
32 |
33 |
--------------------------------------------------------------------------------
/Configurations/Mac OS X/Mac-Application.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for an application on Mac OS X. This should be set at the target level for
4 | // each project configuration.
5 | //
6 |
7 | // Import base application settings
8 | #include "../Base/Targets/Application.xcconfig"
9 |
10 | // Apply common settings specific to Mac OS X
11 | #include "Mac-Base.xcconfig"
12 |
13 | // Whether function calls should be position-dependent (should always be
14 | // disabled for library code)
15 | GCC_DYNAMIC_NO_PIC = YES
16 |
--------------------------------------------------------------------------------
/Configurations/Mac OS X/Mac-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for Mac OS X. This file is not standalone -- it is meant to be included into
4 | // a configuration file for a specific type of target.
5 | //
6 |
7 | // Whether to combine multiple image resolutions into a multirepresentational
8 | // TIFF
9 | COMBINE_HIDPI_IMAGES = YES
10 |
11 | // Where to find embedded frameworks
12 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks
13 |
14 | // The base SDK to use (if no version is specified, the latest version is
15 | // assumed)
16 | SDKROOT = macosx
17 |
18 | // Supported build architectures
19 | VALID_ARCHS = x86_64
20 |
--------------------------------------------------------------------------------
/Configurations/Mac OS X/Mac-DynamicLibrary.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a dynamic library on Mac OS X. This should be set at the target level
4 | // for each project configuration.
5 | //
6 |
7 | // Import common settings specific to Mac OS X
8 | #include "Mac-Base.xcconfig"
9 |
10 | // Whether to strip out code that isn't called from anywhere
11 | DEAD_CODE_STRIPPING = NO
12 |
13 | // Whether function calls should be position-dependent (should always be
14 | // disabled for library code)
15 | GCC_DYNAMIC_NO_PIC = NO
16 |
17 | // Don't include in an xcarchive
18 | SKIP_INSTALL = YES
19 |
--------------------------------------------------------------------------------
/Configurations/Mac OS X/Mac-Framework.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a framework on OS X. This should be set at the target level for each
4 | // project configuration.
5 | //
6 |
7 | // Import base framework settings
8 | #include "../Base/Targets/Framework.xcconfig"
9 |
10 | // Import common settings specific to Mac OS X
11 | #include "Mac-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/Mac OS X/Mac-StaticLibrary.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a static library on Mac OS X. This should be set at the target level for
4 | // each project configuration.
5 | //
6 |
7 | // Import base static library settings
8 | #include "../Base/Targets/StaticLibrary.xcconfig"
9 |
10 | // Apply common settings specific to Mac OS X
11 | #include "Mac-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/iOS/iOS-Application.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for an application on iOS. This should be set at the target level for each
4 | // project configuration.
5 | //
6 |
7 | // Import base application settings
8 | #include "../Base/Targets/Application.xcconfig"
9 |
10 | // Apply common settings specific to iOS
11 | #include "iOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/iOS/iOS-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for iOS. This file is not standalone -- it is meant to be included into
4 | // a configuration file for a specific type of target.
5 | //
6 |
7 | // Xcode needs this to find archived headers if SKIP_INSTALL is set
8 | HEADER_SEARCH_PATHS = $(OBJROOT)/UninstalledProducts/include
9 |
10 | // Where to find embedded frameworks
11 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
12 |
13 | // The base SDK to use (if no version is specified, the latest version is
14 | // assumed)
15 | SDKROOT = iphoneos
16 |
17 | // Supported device families (1 is iPhone, 2 is iPad)
18 | TARGETED_DEVICE_FAMILY = 1,2
19 |
--------------------------------------------------------------------------------
/Configurations/iOS/iOS-Framework.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a framework on iOS. This should be set at the target level for each
4 | // project configuration.
5 | //
6 |
7 | // Import base framework settings
8 | #include "../Base/Targets/Framework.xcconfig"
9 |
10 | // Import common settings specific to iOS
11 | #include "iOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/iOS/iOS-StaticLibrary.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a static library on iOS. This should be set at the target level for each
4 | // project configuration.
5 | //
6 |
7 | // Import base static library settings
8 | #include "../Base/Targets/StaticLibrary.xcconfig"
9 |
10 | // Apply common settings specific to iOS
11 | #include "iOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/tvOS/tvOS-Application.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for an application on tvOS. This should be set at the target level for
4 | // each project configuration.
5 | //
6 |
7 | // Import base application settings
8 | #include "../Base/Targets/Application.xcconfig"
9 |
10 | // Apply common settings specific to tvOS
11 | #include "tvOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/tvOS/tvOS-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for tvOS. This file is not standalone -- it is meant to be included into
4 | // a configuration file for a specific type of target.
5 | //
6 |
7 | // Where to find embedded frameworks
8 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
9 |
10 | // The base SDK to use (if no version is specified, the latest version is
11 | // assumed)
12 | SDKROOT = appletvos
13 |
14 | // Supported device families
15 | TARGETED_DEVICE_FAMILY = 3
16 |
--------------------------------------------------------------------------------
/Configurations/tvOS/tvOS-Framework.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a framework on tvOS. This should be set at the target level for each
4 | // project configuration.
5 | //
6 |
7 | // Import base framework settings
8 | #include "../Base/Targets/Framework.xcconfig"
9 |
10 | // Import common settings specific to iOS
11 | #include "tvOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/tvOS/tvOS-StaticLibrary.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a static library on tvOS. This should be set at the target level for
4 | // each project configuration.
5 | //
6 |
7 | // Import base static library settings
8 | #include "../Base/Targets/StaticLibrary.xcconfig"
9 |
10 | // Apply common settings specific to tvOS
11 | #include "tvOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/watchOS/watchOS-Application.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for an application on watchOS. This should be set at the target level for
4 | // each project configuration.
5 | //
6 |
7 | // Import base application settings
8 | #include "../Base/Targets/Application.xcconfig"
9 |
10 | // Apply common settings specific to watchOS
11 | #include "watchOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/watchOS/watchOS-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for watchOS. This file is not standalone -- it is meant to be included into
4 | // a configuration file for a specific type of target.
5 | //
6 |
7 | // Where to find embedded frameworks
8 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
9 |
10 | // The base SDK to use (if no version is specified, the latest version is
11 | // assumed)
12 | SDKROOT = watchos
13 |
14 | // Supported device families
15 | TARGETED_DEVICE_FAMILY = 4
16 |
--------------------------------------------------------------------------------
/Configurations/watchOS/watchOS-Framework.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a framework on watchOS. This should be set at the target level for each
4 | // project configuration.
5 | //
6 |
7 | // Import base framework settings
8 | #include "../Base/Targets/Framework.xcconfig"
9 |
10 | // Import common settings specific to iOS
11 | #include "watchOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Configurations/watchOS/watchOS-StaticLibrary.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // This file defines additional configuration options that are appropriate only
3 | // for a static library on watchOS. This should be set at the target level for
4 | // each project configuration.
5 | //
6 |
7 | // Import base static library settings
8 | #include "../Base/Targets/StaticLibrary.xcconfig"
9 |
10 | // Apply common settings specific to watchOS
11 | #include "watchOS-Base.xcconfig"
12 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "cocoapods", "1.8.1"
6 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.0)
5 | activesupport (4.2.10)
6 | i18n (~> 0.7)
7 | minitest (~> 5.1)
8 | thread_safe (~> 0.3, >= 0.3.4)
9 | tzinfo (~> 1.1)
10 | atomos (0.1.3)
11 | claide (1.0.2)
12 | cocoapods (1.6.0.beta.1)
13 | activesupport (>= 4.0.2, < 5)
14 | claide (>= 1.0.2, < 2.0)
15 | cocoapods-core (= 1.6.0.beta.1)
16 | cocoapods-deintegrate (>= 1.0.2, < 2.0)
17 | cocoapods-downloader (>= 1.2.1, < 2.0)
18 | cocoapods-plugins (>= 1.0.0, < 2.0)
19 | cocoapods-search (>= 1.0.0, < 2.0)
20 | cocoapods-stats (>= 1.0.0, < 2.0)
21 | cocoapods-trunk (>= 1.3.1, < 2.0)
22 | cocoapods-try (>= 1.1.0, < 2.0)
23 | colored2 (~> 3.1)
24 | escape (~> 0.0.4)
25 | fourflusher (~> 2.0.1)
26 | gh_inspector (~> 1.0)
27 | molinillo (~> 0.6.6)
28 | nap (~> 1.0)
29 | ruby-macho (~> 1.2)
30 | xcodeproj (>= 1.6.0, < 2.0)
31 | cocoapods-core (1.6.0.beta.1)
32 | activesupport (>= 4.0.2, < 6)
33 | fuzzy_match (~> 2.0.4)
34 | nap (~> 1.0)
35 | cocoapods-deintegrate (1.0.2)
36 | cocoapods-downloader (1.2.1)
37 | cocoapods-plugins (1.0.0)
38 | nap
39 | cocoapods-search (1.0.0)
40 | cocoapods-stats (1.0.0)
41 | cocoapods-trunk (1.3.1)
42 | nap (>= 0.8, < 2.0)
43 | netrc (~> 0.11)
44 | cocoapods-try (1.1.0)
45 | colored2 (3.1.2)
46 | concurrent-ruby (1.0.5)
47 | escape (0.0.4)
48 | fourflusher (2.0.1)
49 | fuzzy_match (2.0.4)
50 | gh_inspector (1.1.3)
51 | i18n (0.9.5)
52 | concurrent-ruby (~> 1.0)
53 | minitest (5.11.3)
54 | molinillo (0.6.6)
55 | nanaimo (0.2.6)
56 | nap (1.1.0)
57 | netrc (0.11.0)
58 | ruby-macho (1.3.1)
59 | thread_safe (0.3.6)
60 | tzinfo (1.2.5)
61 | thread_safe (~> 0.1)
62 | xcodeproj (1.6.0)
63 | CFPropertyList (>= 2.3.3, < 4.0)
64 | atomos (~> 0.1.3)
65 | claide (>= 1.0.2, < 2.0)
66 | colored2 (~> 3.1)
67 | nanaimo (~> 0.2.6)
68 |
69 | PLATFORMS
70 | ruby
71 |
72 | DEPENDENCIES
73 | cocoapods (= 1.6.0.beta.1)
74 |
75 | BUNDLED WITH
76 | 1.16.4
77 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Swinject Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Run help command as the default.
3 | #
4 | all: help
5 |
6 | #
7 | # Shows help message.
8 | #
9 | .PHONY: help
10 | help:
11 | @echo 'To release a version of SwinjectStoryboard, run the following commands in order on the branch where you make a release.'
12 | @echo ' $$ make VERSION= set-new-version (e.g. make VERSION=1.2.3 set-new-version)'
13 | @echo ' $$ make [UPSTREAM=] push-to-upstream (e.g. make push-to-upstream)'
14 | @echo ' $$ make carthage-release'
15 | @echo ' $$ make cocoapods-release'
16 |
17 | #
18 | # Set a specified version in Info.plist and podspec files, and tag the version.
19 | #
20 | .PHONY: set-new-version
21 | set-new-version:
22 | ifndef VERSION
23 | $(error Specify a new version. E.g. $$ make VERSION=1.2.3 set-new-version)
24 | endif
25 | ifeq ($(wildcard ./SwinjectStoryboard.podspec),)
26 | $(error Run the command in the directory containing SwinjectStoryboard.podspec.)
27 | endif
28 | ifeq ($(shell git diff --quiet; echo $$?), 1)
29 | $(error Your current git working tree is dirty. Stash all to run this command.)
30 | endif
31 | agvtool new-marketing-version $(VERSION)
32 | sed -i '' -e 's/\(s\.version.*=\).*/\1 "$(VERSION)"/' ./SwinjectStoryboard.podspec
33 | git commit -a -m "Update the version to $(VERSION)"
34 | git tag $(VERSION)
35 |
36 | #
37 | # Push the commit and tag for the new version to upstream.
38 | #
39 | VERSION_TAG=$(shell git describe --tags --abbrev=0)
40 | ifndef UPSTREAM
41 | UPSTREAM=upstream
42 | endif
43 | .PHONY: push-to-upstream
44 | push-to-upstream:
45 | git push $(UPSTREAM) $(shell git rev-parse --abbrev-ref HEAD)
46 | git push $(UPSTREAM) $(VERSION_TAG)
47 |
48 | #
49 | # Make a release for Carthage.
50 | #
51 | VERSION_TAG=$(shell git describe --tags --abbrev=0)
52 | .PHONY: carthage-release
53 | carthage-release:
54 | ifeq ($(shell which gh),)
55 | $(error gh command not found. Install gh command and run `gh auth login` beforehand.)
56 | endif
57 | ifneq ($(VERSION_TAG),$(shell agvtool what-marketing-version -terse1))
58 | $(error The version tag $(VERSION_TAG) does not match the version in Info.plist)
59 | endif
60 | gh release create $(VERSION_TAG) --draft --title v$(VERSION_TAG) --notes ""
61 | @echo Open https://github.com/Swinject/SwinjectStoryboard/releases/edit/$(VERSION_TAG) to describe the release and publish it.
62 |
63 | #
64 | # Make a release for Cocoapods.
65 | #
66 | .PHONY: cocoapods-release
67 | cocoapods-release:
68 | pod lib lint
69 | pod trunk push SwinjectStoryboard.podspec
70 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "Swinject",
6 | "repositoryURL": "https://github.com/Swinject/Swinject.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "8a76d2c74bafbb455763487cc6a08e91bad1f78b",
10 | "version": "2.7.1"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "SwinjectStoryboard",
6 | platforms: [
7 | .macOS(.v10_10),
8 | .iOS(.v9),
9 | .tvOS(.v9),
10 | ],
11 | products: [
12 | .library(name: "SwinjectStoryboard", targets: ["SwinjectStoryboard"]),
13 | ],
14 | dependencies: [
15 | .package(url: "https://github.com/Swinject/Swinject.git", .upToNextMajor(from: "2.7.1")),
16 | ],
17 | targets: [
18 | .target(
19 | name: "SwinjectStoryboard-ObjC",
20 | path: "Sources/ObjectiveC",
21 | cSettings: [
22 | .headerSearchPath("Others")
23 | ]
24 | ),
25 | .target(
26 | name: "SwinjectStoryboard",
27 | dependencies: [
28 | "Swinject",
29 | "SwinjectStoryboard-ObjC"
30 | ],
31 | path: "Sources",
32 | exclude: [
33 | "ObjectiveC",
34 | "Info.plist"
35 | ]
36 | ),
37 | ]
38 | )
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SwinjectStoryboard
2 | ========
3 |
4 | [](https://travis-ci.org/Swinject/SwinjectStoryboard)
5 | [](https://github.com/Carthage/Carthage)
6 | [](http://cocoapods.org/pods/SwinjectStoryboard)
7 | [](http://cocoapods.org/pods/SwinjectStoryboard)
8 | [](http://cocoapods.org/pods/SwinjectStoryboard)
9 | [](https://developer.apple.com/swift)
10 | [](https://github.com/apple/swift-package-manager)
11 |
12 | SwinjectStoryboard is an extension of Swinject to automatically inject dependency to view controllers instantiated by a storyboard.
13 |
14 | ## Requirements
15 |
16 | - iOS 8.0+ / Mac OS X 10.10+ / tvOS 9.0+
17 | - Xcode 8+
18 |
19 | ## Installation
20 |
21 | Swinject is available through [Carthage](https://github.com/Carthage/Carthage) or [CocoaPods](https://cocoapods.org).
22 |
23 | ### Carthage
24 |
25 | To install Swinject with Carthage, add the following line to your `Cartfile`.
26 |
27 | ```
28 | github "Swinject/Swinject"
29 | github "Swinject/SwinjectStoryboard"
30 | ```
31 |
32 | Then run `carthage update --no-use-binaries` command or just `carthage update`. For details of the installation and usage of Carthage, visit [its project page](https://github.com/Carthage/Carthage).
33 |
34 | ### CocoaPods
35 |
36 | To install Swinject with CocoaPods, add the following lines to your `Podfile`.
37 |
38 | ```ruby
39 | source 'https://github.com/CocoaPods/Specs.git'
40 | platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
41 | use_frameworks!
42 |
43 | pod 'Swinject'
44 | pod 'SwinjectStoryboard'
45 | ```
46 |
47 | Then run `pod install` command. For details of the installation and usage of CocoaPods, visit [its official website](https://cocoapods.org).
48 |
49 | ### Swift Package Manager
50 |
51 | To integrate using Apple's Swift package manager, add the following as a dependency to your `Package.swift`:
52 |
53 | ```swift
54 | .package(url: "https://github.com/Swinject/SwinjectStoryboard.git", .upToNextMajor(from: "2.2.0"))
55 | ```
56 |
57 | and then specify `"SwinjectStoryboard"` as a dependency of the Target in which you wish to use SwinjectStoryboard.
58 |
59 | ## Usage
60 |
61 | Swinject supports automatic dependency injection to view controllers instantiated by `SwinjectStoryboard`. This class inherits `UIStoryboard` (or `NSStoryboard` in case of OS X). To register dependencies of a view controller, use `storyboardInitCompleted` method. In the same way as a registration of a service type, a view controller can be registered with or without a name.
62 |
63 | **NOTE**: Do NOT explicitly resolve the view controllers registered by `storyboardInitCompleted` method. The view controllers are intended to be resolved by `SwinjectStoryboard` implicitly.
64 |
65 | ### Registration
66 |
67 | #### Registration without Name
68 |
69 | Here is a simple example to register a dependency of a view controller without a registration name:
70 |
71 | ```swift
72 | let container = Container()
73 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
74 | c.animal = r.resolve(Animal.self)
75 | }
76 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
77 | ```
78 |
79 | Next, we create an instance of `SwinjectStoryboard` with the container specified. If the container is not specified, `SwinjectStoryboard.defaultContainer` is used instead. `instantiateViewControllerWithIdentifier` method creates an instance of the view controller with its dependencies injected:
80 |
81 | ```swift
82 | let sb = SwinjectStoryboard.create(
83 | name: "Animals", bundle: nil, container: container)
84 | let controller = sb.instantiateViewControllerWithIdentifier("Animal")
85 | as! AnimalViewController
86 | print(controller.animal! is Cat) // prints "true"
87 | print(controller.animal!.name) // prints "Mimi"
88 | ```
89 |
90 | Where the classes and protocol are:
91 |
92 | ```swift
93 | class AnimalViewController: UIViewController {
94 | var animal: Animal?
95 |
96 | required init?(coder aDecoder: NSCoder) {
97 | super.init(coder: aDecoder)
98 | }
99 | }
100 |
101 | protocol Animal {
102 | var name: String { get set }
103 | }
104 |
105 | class Cat: Animal {
106 | var name: String
107 |
108 | init(name: String) {
109 | self.name = name
110 | }
111 | }
112 | ```
113 |
114 | and the storyboard named `Animals.storyboard` has `AnimalViewController` with storyboard ID `Animal`.
115 |
116 | 
117 |
118 | #### Registration with Name
119 |
120 | If a storyboard has more than one view controller with the same type, dependencies should be registered with registration names.
121 |
122 | ```swift
123 | let container = Container()
124 | container.storyboardInitCompleted(AnimalViewController.self, name: "cat") {
125 | r, c in c.animal = r.resolve(Animal.self, name: "mimi")
126 | }
127 | container.storyboardInitCompleted(AnimalViewController.self, name: "dog") {
128 | r, c in c.animal = r.resolve(Animal.self, name: "hachi")
129 | }
130 | container.register(Animal.self, name: "mimi") {
131 | _ in Cat(name: "Mimi")
132 | }
133 | container.register(Animal.self, name: "hachi") {
134 | _ in Dog(name: "Hachi")
135 | }
136 | ```
137 |
138 | Then view controllers are instantiated with storyboard IDs similarly to the case without registration names:
139 |
140 | ```swift
141 | let sb = SwinjectStoryboard.create(
142 | name: "Animals", bundle: nil, container: container)
143 | let catController = sb.instantiateViewControllerWithIdentifier("Cat")
144 | as! AnimalViewController
145 | let dogController = sb.instantiateViewControllerWithIdentifier("Dog")
146 | as! AnimalViewController
147 | print(catController.animal!.name) // prints "Mimi"
148 | print(dogController.animal!.name) // prints "Hachi"
149 | ```
150 |
151 | Where `Dog` class is:
152 |
153 | ```swift
154 | class Dog: Animal {
155 | var name: String
156 |
157 | init(name: String) {
158 | self.name = name
159 | }
160 | }
161 | ```
162 |
163 | and the storyboard named `Animals.storyboard` has `AnimalViewController`s with storyboard IDs `Cat` and `Dog`. In addition to the storyboard IDs, user defined runtime attributes are specified as `cat` and `dog` for the key `swinjectRegistrationName`, respectively.
164 |
165 | 
166 |
167 | ### UIWindow and Root View Controller Instantiation
168 |
169 | #### Implicit Instantiation from "Main" Storyboard
170 |
171 | If you implicitly instantiate `UIWindow` and its root view controller from "Main" storyboard, implement `setup` class method as an extension of `SwinjectStoryboard` to register dependencies to `defaultContainer`. When the root view controller (initial view controller) is instantiated by runtime, dependencies registered to `defaultContainer` are injected.
172 |
173 | **Note that `@objc` attribute is mandatory here in swift 4.**
174 |
175 | ```swift
176 | extension SwinjectStoryboard {
177 | @objc class func setup() {
178 | defaultContainer.storyboardInitCompleted(AnimalViewController.self) { r, c in
179 | c.animal = r.resolve(Animal.self)
180 | }
181 | defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
182 | }
183 | }
184 | ```
185 |
186 | #### Explicit Instantiation in AppDelegate
187 |
188 | If you prefer explicit instantiation of UIWindow and its root view controller, instantiate `SwinjectStoryboard` with a container in `application:didFinishLaunchingWithOptions:` method.
189 |
190 | ```swift
191 | @UIApplicationMain
192 | class AppDelegate: UIResponder, UIApplicationDelegate {
193 | var window: UIWindow?
194 | var container: Container = {
195 | let container = Container()
196 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
197 | c.animal = r.resolve(Animal.self)
198 | }
199 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
200 | return container
201 | }()
202 |
203 | func application(
204 | _ application: UIApplication,
205 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
206 |
207 | let window = UIWindow(frame: UIScreen.mainScreen().bounds)
208 | window.makeKeyAndVisible()
209 | self.window = window
210 |
211 | let storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil, container: container)
212 | window.rootViewController = storyboard.instantiateInitialViewController()
213 |
214 | return true
215 | }
216 | }
217 | ```
218 |
219 | Notice that you should delete the `Main storyboard file base name` item (or `UIMainStoryboardFile` item if you are displaying raw keys/values) in `Info.plist` of your app.
220 |
221 | ### Storyboard References
222 |
223 | Storyboard Reference introduced with Xcode 7 is supported by `SwinjectStoryboard`. To enable dependency injection when an instance is created from a referenced storyboard, register dependencies to `defaultContainer` static property of `SwinjectStoryboard`.
224 |
225 | ```swift
226 | let container = SwinjectStoryboard.defaultContainer
227 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
228 | c.animal = r.resolve(Animal.self)
229 | }
230 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
231 | ```
232 |
233 | If you implicitly instantiate `UIWindow` and its root view controller, the registrations setup for "Main" storyboard can be shared with the referenced storyboard since `defaultContainer` is configured in `setup` method.
234 |
235 | ## For Maintainers
236 |
237 | ### Making a new release version
238 |
239 | Our release procedure is described as [Makefile](https://github.com/Swinject/SwinjectStoryboard/blob/master/Makefile). Run `make help` command for more info.
240 |
241 | ## Credits
242 |
243 | SwinjectStoryboard is inspired by:
244 |
245 | - [Typhoon](https://github.com/appsquickly/typhoon) - [Jasper Blues](https://github.com/jasperblues), [Aleksey Garbarev](https://github.com/alexgarbarev) and [contributors](https://github.com/appsquickly/Typhoon/graphs/contributors).
246 | - [BlindsidedStoryboard](https://github.com/briancroom/BlindsidedStoryboard) - [Brian Croom](https://github.com/briancroom).
247 |
248 | ## License
249 |
250 | MIT license. See the [LICENSE file](LICENSE.txt) for details.
251 |
--------------------------------------------------------------------------------
/Sources/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 11/27/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | internal final class Box {
12 | internal let value: T
13 |
14 | internal init(_ value: T) {
15 | self.value = value
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/Container+SwinjectStoryboard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Container+SwinjectStoryboard.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 11/28/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | #if canImport(UIKit)
10 | import UIKit
11 | #endif
12 | import Swinject
13 |
14 | #if os(iOS) || os(OSX) || os(tvOS)
15 | extension Container {
16 | /// Adds a registration of the specified view or window controller that is configured in a storyboard.
17 | ///
18 | /// - Note: Do NOT explicitly resolve the controller registered by this method.
19 | /// The controller is intended to be resolved by `SwinjectStoryboard` implicitly.
20 | ///
21 | /// - Parameters:
22 | /// - controllerType: The controller type to register as a service type.
23 | /// The type is `UIViewController` in iOS, `NSViewController` or `NSWindowController` in OS X.
24 | /// - name: A registration name, which is used to differentiate from other registrations
25 | /// that have the same view or window controller type.
26 | /// - initCompleted: A closure to specify how the dependencies of the view or window controller are injected.
27 | /// It is invoked by the `Container` when the view or window controller is instantiated by `SwinjectStoryboard`.
28 | public func storyboardInitCompleted(_ controllerType: C.Type, name: String? = nil, initCompleted: @escaping (Resolver, C) -> ()) {
29 | // Xcode 7.1 workaround for Issue #10. This workaround is not necessary with Xcode 7.
30 | // https://github.com/Swinject/Swinject/issues/10
31 | let factory = { (_: Resolver, controller: Controller) in controller }
32 | let wrappingClosure: (Resolver, Controller) -> () = { r, c in initCompleted(r, c as! C) }
33 | let option = SwinjectStoryboardOption(controllerType: controllerType)
34 | _register(Controller.self, factory: factory, name: name, option: option)
35 | .initCompleted(wrappingClosure)
36 | }
37 | }
38 | #endif
39 |
40 |
41 | extension Container {
42 | #if os(iOS) || os(tvOS)
43 | /// The typealias to UIViewController.
44 | public typealias Controller = UIViewController
45 |
46 | #elseif os(OSX)
47 | /// The typealias to AnyObject, which should be actually NSViewController or NSWindowController.
48 | /// See the reference of NSStoryboard.instantiateInitialController method.
49 | public typealias Controller = Any
50 |
51 | #endif
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/DispatchQueue+Once.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | internal extension DispatchQueue {
4 |
5 | private static var _onceTracker: [String] = []
6 |
7 | static func once(token: String, block: () -> Void) {
8 | objc_sync_enter(self)
9 | defer { objc_sync_exit(self) }
10 |
11 | if _onceTracker.contains(token) {
12 | return
13 | }
14 |
15 | _onceTracker.append(token)
16 | block()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.2.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2016 Swinject Contributors. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Sources/InjectionVerifiable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InjectionVerifiable.swift
3 | // Swinject
4 | //
5 | // Created by Jakub Vaňo on 28/10/16.
6 | // Copyright © 2016 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | @objc internal protocol InjectionVerifiable: AnyObject {
12 | var wasInjected: Bool { get set }
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/OSX/NSStoryboard+Swizzling.swift:
--------------------------------------------------------------------------------
1 | #if canImport(Cocoa) && !targetEnvironment(macCatalyst)
2 | import Cocoa
3 |
4 | extension NSStoryboard {
5 | static func swizzling() {
6 | DispatchQueue.once(token: "swinject.storyboard.init") {
7 | let aClass: AnyClass = object_getClass(self)!
8 |
9 | let originalSelector = #selector(NSStoryboard.init(name:bundle:))
10 | let swizzledSelector = #selector(swinject_init(name:bundle:))
11 |
12 | let originalMethod = class_getInstanceMethod(aClass, originalSelector)!
13 | let swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector)!
14 |
15 | let didAddMethod = class_addMethod(aClass, originalSelector,
16 | method_getImplementation(swizzledMethod),
17 | method_getTypeEncoding(swizzledMethod))
18 |
19 | guard didAddMethod else {
20 | method_exchangeImplementations(originalMethod, swizzledMethod)
21 | return
22 | }
23 | class_replaceMethod(aClass, swizzledSelector,
24 | method_getImplementation(originalMethod),
25 | method_getTypeEncoding(originalMethod))
26 | }
27 | }
28 |
29 | @objc class func swinject_init(name: String, bundle: Bundle?) -> NSStoryboard {
30 | guard self == NSStoryboard.self else {
31 | return self.swinject_init(name: name, bundle: bundle)
32 | }
33 | // Instantiate SwinjectStoryboard if NSStoryboard is trying to be instantiated.
34 | if SwinjectStoryboard.isCreatingStoryboardReference {
35 | return SwinjectStoryboard.createReferenced(name: name, bundle: bundle)
36 | } else {
37 | return SwinjectStoryboard.create(name: name, bundle: bundle)
38 | }
39 | }
40 | }
41 | #endif
42 |
--------------------------------------------------------------------------------
/Sources/OSX/_SwinjectStoryboardBase(OSX).swift:
--------------------------------------------------------------------------------
1 | #if canImport(Cocoa) && !targetEnvironment(macCatalyst)
2 | import Cocoa
3 | import Swinject
4 |
5 | @objcMembers
6 | public class _SwinjectStoryboardBase: NSStoryboard {
7 | public class func _create(_ name: String, bundle storyboardBundleOrNil: Bundle?) -> Self {
8 | let storyboard = perform(#selector(NSStoryboard.init(name:bundle:)), with: name, with: storyboardBundleOrNil)?
9 | .takeUnretainedValue()
10 | return storyboard as! Self
11 | }
12 | }
13 |
14 | extension SwinjectStoryboard {
15 | @objc public static func configure() {
16 | NSStoryboard.swizzling()
17 | DispatchQueue.once(token: "swinject.storyboard.setup") {
18 | guard SwinjectStoryboard.responds(to: _Selector("setup")) else { return }
19 | SwinjectStoryboard.perform(_Selector("setup"))
20 | }
21 | }
22 |
23 | static func _Selector(_ str: String) -> Selector {
24 | return Selector(str)
25 | }
26 | }
27 | #endif
28 |
--------------------------------------------------------------------------------
/Sources/ObjectiveC/Others/SwinjectStoryboard+SetUp.m:
--------------------------------------------------------------------------------
1 | //
2 | // SwinjectStoryboard+SetUp.m
3 | // SwinjectStoryboard
4 | //
5 | // Created by Mark DiFranco on 2017-05-27.
6 | // Copyright © 2017 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | __attribute__((constructor)) static void swinjectStoryboardSetupEntry(void) {
12 | Class swinjectStoryboard = NSClassFromString(@"SwinjectStoryboard");
13 | #pragma clang diagnostic push
14 | #pragma clang diagnostic ignored "-Wundeclared-selector"
15 | if ([swinjectStoryboard respondsToSelector:@selector(configure)]) {
16 | [swinjectStoryboard performSelector:@selector(configure)];
17 | }
18 | #pragma clang diagnostic pop
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/Sources/RegistrationNameAssociatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RegistrationNameAssociatable.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 8/1/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | @objc internal protocol RegistrationNameAssociatable: AnyObject {
12 | var swinjectRegistrationName: String? { get set }
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/SwinjectStoryboard+StoryboardReference.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwinjectStoryboard+StoryboardReference.
3 | // SwinjectStoryboard
4 | //
5 | // Created by Jakub Vaňo on 01/09/16.
6 | // Copyright © 2016 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if canImport(UIKit)
11 | import UIKit
12 | #elseif canImport(Cocoa)
13 | import Cocoa
14 | #endif
15 |
16 | internal extension SwinjectStoryboard {
17 |
18 | static func pushInstantiatingStoryboard(_ storyboard: SwinjectStoryboard) {
19 | storyboardStack.append(storyboard)
20 | }
21 |
22 | @discardableResult
23 | static func popInstantiatingStoryboard() -> SwinjectStoryboard? {
24 | return storyboardStack.popLast()
25 | }
26 |
27 | class var isCreatingStoryboardReference: Bool {
28 | return referencingStoryboard != nil
29 | }
30 |
31 | static var referencingStoryboard: SwinjectStoryboard? {
32 | return storyboardStack.last
33 | }
34 | #if os(iOS) || os(tvOS)
35 | class func createReferenced(name: String, bundle storyboardBundleOrNil: Bundle?) -> SwinjectStoryboard {
36 | if let container = referencingStoryboard?.container.value {
37 | return create(name: name, bundle: storyboardBundleOrNil, container: container)
38 | } else {
39 | return create(name: name, bundle: storyboardBundleOrNil)
40 | }
41 | }
42 | #elseif os(OSX)
43 | class func createReferenced(name: NSStoryboard.Name, bundle storyboardBundleOrNil: Bundle?) -> SwinjectStoryboard {
44 | if let container = referencingStoryboard?.container.value {
45 | return create(name: name, bundle: storyboardBundleOrNil, container: container)
46 | } else {
47 | return create(name: name, bundle: storyboardBundleOrNil)
48 | }
49 | }
50 | #endif
51 | }
52 |
53 | private var storyboardStack = [SwinjectStoryboard]()
54 |
--------------------------------------------------------------------------------
/Sources/SwinjectStoryboard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwinjectStoryboard.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 7/31/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Swinject
10 | #if canImport(UIKit)
11 | import UIKit
12 | #elseif canImport(Cocoa)
13 | import Cocoa
14 | #endif
15 |
16 | #if os(iOS) || os(tvOS) || os(OSX)
17 |
18 | /// The `SwinjectStoryboard` provides the features to inject dependencies of view/window controllers in a storyboard.
19 | ///
20 | /// To specify a registration name of a view/window controller registered to the `Container` as a service type,
21 | /// add a user defined runtime attribute with the following settings:
22 | ///
23 | /// - Key Path: `swinjectRegistrationName`
24 | /// - Type: String
25 | /// - Value: Registration name to the `Container`
26 | ///
27 | /// in User Defined Runtime Attributes section on Indentity Inspector pane.
28 | /// If no name is supplied to the registration, no runtime attribute should be specified.
29 | @objcMembers
30 | @objc(SwinjectStoryboard)
31 | public class SwinjectStoryboard: _SwinjectStoryboardBase, SwinjectStoryboardProtocol {
32 | /// A shared container used by SwinjectStoryboard instances that are instantiated without specific containers.
33 | ///
34 | /// Typical usecases of this property are:
35 | /// - Implicit instantiation of UIWindow and its root view controller from "Main" storyboard.
36 | /// - Storyboard references to transit from a storyboard to another.
37 | public static var defaultContainer = Container()
38 |
39 | // Boxing to workaround a runtime error [Xcode 7.1.1 and Xcode 7.2 beta 4]
40 | // If container property is Resolver type and a Resolver instance is assigned to the property,
41 | // the program crashes by EXC_BAD_ACCESS, which looks a bug of Swift.
42 | internal var container: Box!
43 |
44 | private override init() {
45 | super.init()
46 | }
47 |
48 | #if os(iOS) || os(tvOS)
49 | /// Creates the new instance of `SwinjectStoryboard`. This method is used instead of an initializer.
50 | ///
51 | /// - Parameters:
52 | /// - name: The name of the storyboard resource file without the filename extension.
53 | /// - storyboardBundleOrNil: The bundle containing the storyboard file and its resources. Specify nil to use the main bundle.
54 | ///
55 | /// - Note:
56 | /// The shared singleton container `SwinjectStoryboard.defaultContainer` is used as the container.
57 | ///
58 | /// - Returns: The new instance of `SwinjectStoryboard`.
59 | public class func create(
60 | name: String,
61 | bundle storyboardBundleOrNil: Bundle?) -> SwinjectStoryboard {
62 | return SwinjectStoryboard.create(name: name, bundle: storyboardBundleOrNil,
63 | container: SwinjectStoryboard.defaultContainer)
64 | }
65 |
66 | /// Creates the new instance of `SwinjectStoryboard`. This method is used instead of an initializer.
67 | ///
68 | /// - Parameters:
69 | /// - name: The name of the storyboard resource file without the filename extension.
70 | /// - storyboardBundleOrNil: The bundle containing the storyboard file and its resources. Specify nil to use the main bundle.
71 | /// - container: The container with registrations of the view/window controllers in the storyboard and their dependencies.
72 | ///
73 | /// - Returns: The new instance of `SwinjectStoryboard`.
74 | public class func create(
75 | name: String,
76 | bundle storyboardBundleOrNil: Bundle?,
77 | container: Resolver) -> SwinjectStoryboard
78 | {
79 | // Use this factory method to create an instance because the initializer of UI/NSStoryboard is "not inherited".
80 | let storyboard = SwinjectStoryboard._create(name, bundle: storyboardBundleOrNil)
81 | storyboard.container = Box(container)
82 | return storyboard
83 | }
84 |
85 | /// Instantiates the view controller with the specified identifier.
86 | /// The view controller and its child controllers have their dependencies injected
87 | /// as specified in the `Container` passed to the initializer of the `SwinjectStoryboard`.
88 | ///
89 | /// - Parameter identifier: The identifier set in the storyboard file.
90 | ///
91 | /// - Returns: The instantiated view controller with its dependencies injected.
92 | public override func instantiateViewController(withIdentifier identifier: String) -> UIViewController {
93 | SwinjectStoryboard.pushInstantiatingStoryboard(self)
94 | let viewController = super.instantiateViewController(withIdentifier: identifier)
95 | SwinjectStoryboard.popInstantiatingStoryboard()
96 |
97 | injectDependency(to: viewController)
98 |
99 | return viewController
100 | }
101 |
102 | private func injectDependency(to viewController: UIViewController) {
103 | guard !viewController.wasInjected else { return }
104 | defer { viewController.wasInjected = true }
105 |
106 | let registrationName = viewController.swinjectRegistrationName
107 |
108 | // Xcode 7.1 workaround for Issue #10. This workaround is not necessary with Xcode 7.
109 | // If a future update of Xcode fixes the problem, replace the resolution with the following code and fix storyboardInitCompleted too.
110 | // https://github.com/Swinject/Swinject/issues/10
111 | if let container = container.value as? _Resolver {
112 | let option = SwinjectStoryboardOption(controllerType: type(of: viewController))
113 | typealias FactoryType = ((Resolver, Container.Controller)) -> Any
114 | let _ = container._resolve(name: registrationName, option: option) { (factory: FactoryType) in factory((self.container.value, viewController)) as Any } as Container.Controller?
115 | } else {
116 | fatalError("A type conforming Resolver protocol must conform _Resolver protocol too.")
117 | }
118 |
119 | #if swift(>=4.2)
120 | for child in viewController.children {
121 | injectDependency(to: child)
122 | }
123 | #else
124 | for child in viewController.childViewControllers {
125 | injectDependency(to: child)
126 | }
127 | #endif
128 | }
129 |
130 | #elseif os(OSX)
131 | /// Creates the new instance of `SwinjectStoryboard`. This method is used instead of an initializer.
132 | ///
133 | /// - Parameters:
134 | /// - name: The name of the storyboard resource file without the filename extension.
135 | /// - storyboardBundleOrNil: The bundle containing the storyboard file and its resources. Specify nil to use the main bundle.
136 | ///
137 | /// - Note:
138 | /// The shared singleton container `SwinjectStoryboard.defaultContainer` is used as the container.
139 | ///
140 | /// - Returns: The new instance of `SwinjectStoryboard`.
141 | public class func create(
142 | name: NSStoryboard.Name,
143 | bundle storyboardBundleOrNil: Bundle?) -> SwinjectStoryboard {
144 | return SwinjectStoryboard.create(name: name, bundle: storyboardBundleOrNil,
145 | container: SwinjectStoryboard.defaultContainer)
146 | }
147 |
148 | /// Creates the new instance of `SwinjectStoryboard`. This method is used instead of an initializer.
149 | ///
150 | /// - Parameters:
151 | /// - name: The name of the storyboard resource file without the filename extension.
152 | /// - storyboardBundleOrNil: The bundle containing the storyboard file and its resources. Specify nil to use the main bundle.
153 | /// - container: The container with registrations of the view/window controllers in the storyboard and their dependencies.
154 | ///
155 | /// - Returns: The new instance of `SwinjectStoryboard`.
156 | public class func create(
157 | name: NSStoryboard.Name,
158 | bundle storyboardBundleOrNil: Bundle?,
159 | container: Resolver) -> SwinjectStoryboard
160 | {
161 | // Use this factory method to create an instance because the initializer of UI/NSStoryboard is "not inherited".
162 | let storyboard = SwinjectStoryboard._create(name, bundle: storyboardBundleOrNil)
163 | storyboard.container = Box(container)
164 | return storyboard
165 | }
166 |
167 | /// Instantiates the view/Window controller with the specified identifier.
168 | /// The view/window controller and its child controllers have their dependencies injected
169 | /// as specified in the `Container` passed to the initializer of the `SwinjectStoryboard`.
170 | ///
171 | /// - Parameter identifier: The identifier set in the storyboard file.
172 | ///
173 | /// - Returns: The instantiated view/window controller with its dependencies injected.
174 | public override func instantiateController(withIdentifier identifier: NSStoryboard.SceneIdentifier) -> Any {
175 | SwinjectStoryboard.pushInstantiatingStoryboard(self)
176 | let controller = super.instantiateController(withIdentifier: identifier)
177 | SwinjectStoryboard.popInstantiatingStoryboard()
178 |
179 | injectDependency(to: controller)
180 |
181 | return controller
182 | }
183 |
184 | private func injectDependency(to controller: Container.Controller) {
185 | guard let controller = controller as? InjectionVerifiable, !controller.wasInjected else { return }
186 | defer { controller.wasInjected = true }
187 |
188 | let registrationName = (controller as? RegistrationNameAssociatable)?.swinjectRegistrationName
189 |
190 | // Xcode 7.1 workaround for Issue #10. This workaround is not necessary with Xcode 7.
191 | // If a future update of Xcode fixes the problem, replace the resolution with the following code and fix storyboardInitCompleted too:
192 | // https://github.com/Swinject/Swinject/issues/10
193 | if let container = container.value as? _Resolver {
194 | let option = SwinjectStoryboardOption(controllerType: type(of: controller))
195 | typealias FactoryType = ((Resolver, Container.Controller)) -> Any
196 | let _ = container._resolve(name: registrationName, option: option) { (factory: FactoryType) -> Any in factory((self.container.value, controller)) } as Container.Controller?
197 | } else {
198 | fatalError("A type conforming Resolver protocol must conform _Resolver protocol too.")
199 | }
200 | if let windowController = controller as? NSWindowController, let viewController = windowController.contentViewController {
201 | injectDependency(to: viewController)
202 | }
203 | if let viewController = controller as? NSViewController {
204 | #if swift(>=4.2)
205 | for child in viewController.children {
206 | injectDependency(to: child)
207 | }
208 | #else
209 | for child in viewController.childViewControllers {
210 | injectDependency(to: child)
211 | }
212 | #endif
213 | }
214 | }
215 | #endif
216 | }
217 |
218 | #endif
219 |
--------------------------------------------------------------------------------
/Sources/SwinjectStoryboardOption.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwinjectStoryboardOption.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 2/28/16.
6 | // Copyright © 2016 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Swinject
10 |
11 | #if os(iOS) || os(OSX) || os(tvOS)
12 | internal struct SwinjectStoryboardOption: ServiceKeyOption {
13 | internal let controllerType: String
14 |
15 | internal init(controllerType: Container.Controller.Type) {
16 | self.controllerType = String(reflecting: controllerType)
17 | }
18 |
19 | internal func isEqualTo(_ another: ServiceKeyOption) -> Bool {
20 | guard let another = another as? SwinjectStoryboardOption else {
21 | return false
22 | }
23 |
24 | return self.controllerType == another.controllerType
25 | }
26 |
27 | internal var hashValue: Int {
28 | return controllerType.hashValue
29 | }
30 |
31 | internal var description: String {
32 | return "Storyboard: \(controllerType)"
33 | }
34 |
35 | func hash(into: inout Hasher) {
36 | into.combine(controllerType)
37 | }
38 | }
39 | #endif
40 |
--------------------------------------------------------------------------------
/Sources/SwinjectStoryboardProtocol.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | @objc
4 | public protocol SwinjectStoryboardProtocol {
5 |
6 | /// Called by Swinject framework once before SwinjectStoryboard is instantiated.
7 | ///
8 | /// - Note:
9 | /// Implement this method and setup the default container if you implicitly instantiate UIWindow
10 | /// and its root view controller from "Main" storyboard.
11 | ///
12 | /// ```swift
13 | /// extension SwinjectStoryboard {
14 | /// @objc class func setup() {
15 | /// let container = defaultContainer
16 | /// container.register(SomeType.self) {
17 | /// _ in
18 | /// SomeClass()
19 | /// }
20 | /// container.storyboardInitCompleted(ViewController.self) {
21 | /// r, c in
22 | /// c.something = r.resolve(SomeType.self)
23 | /// }
24 | /// }
25 | /// }
26 | /// ```
27 | @objc optional static func setup()
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/UnavailableItems.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UnavailableItems.swift
3 | // SwinjectStoryboard
4 | //
5 | // Created by Yoichi Tagaya on 12/10/16.
6 | // Copyright © 2016 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | // MARK: For auto migration to Swinject v1.
10 | @available(*, unavailable, renamed: "SwinjectStoryboardProtocol")
11 | public protocol SwinjectStoryboardType { }
12 |
--------------------------------------------------------------------------------
/Sources/ViewController+Swinject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController+Swinject.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 7/31/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import ObjectiveC
10 |
11 | #if canImport(UIKit)
12 | import UIKit
13 |
14 | private var uivcRegistrationNameKey: String = "UIViewController.swinjectRegistrationName"
15 | private var uivcWasInjectedKey: String = "UIViewController.wasInjected"
16 |
17 | extension UIViewController: RegistrationNameAssociatable, InjectionVerifiable {
18 | public var swinjectRegistrationName: String? {
19 | get { return getAssociatedString(key: &uivcRegistrationNameKey) }
20 | set { setAssociatedString(newValue, key: &uivcRegistrationNameKey) }
21 | }
22 |
23 | public var wasInjected: Bool {
24 | get { return getAssociatedBool(key: &uivcWasInjectedKey) ?? false }
25 | set { setAssociatedBool(newValue, key: &uivcWasInjectedKey) }
26 | }
27 | }
28 |
29 | #elseif canImport(Cocoa)
30 | import Cocoa
31 |
32 | private var nsvcRegistrationNameKey: String = "NSViewController.swinjectRegistrationName"
33 | private var nswcRegistrationNameKey: String = "NSWindowController.swinjectRegistrationName"
34 | private var nsvcWasInjectedKey: String = "NSViewController.wasInjected"
35 | private var nswcWasInjectedKey: String = "NSWindowController.wasInjected"
36 |
37 | extension NSViewController: RegistrationNameAssociatable, InjectionVerifiable {
38 | internal var swinjectRegistrationName: String? {
39 | get { return getAssociatedString(key: &nsvcRegistrationNameKey) }
40 | set { setAssociatedString(newValue, key: &nsvcRegistrationNameKey) }
41 | }
42 |
43 | internal var wasInjected: Bool {
44 | get { return getAssociatedBool(key: &nsvcWasInjectedKey) ?? false }
45 | set { setAssociatedBool(newValue, key: &nsvcWasInjectedKey) }
46 | }
47 | }
48 |
49 | extension NSWindowController: RegistrationNameAssociatable, InjectionVerifiable {
50 | internal var swinjectRegistrationName: String? {
51 | get { return getAssociatedString(key: &nsvcRegistrationNameKey) }
52 | set { setAssociatedString(newValue, key: &nsvcRegistrationNameKey) }
53 | }
54 |
55 | internal var wasInjected: Bool {
56 | get { return getAssociatedBool(key: &nswcWasInjectedKey) ?? false }
57 | set { setAssociatedBool(newValue, key: &nswcWasInjectedKey) }
58 | }
59 | }
60 |
61 | #endif
62 |
63 | extension NSObject {
64 | fileprivate func getAssociatedString(key: UnsafeRawPointer) -> String? {
65 | return objc_getAssociatedObject(self, key) as? String
66 | }
67 |
68 | fileprivate func setAssociatedString(_ string: String?, key: UnsafeRawPointer) {
69 | objc_setAssociatedObject(self, key, string, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
70 | }
71 |
72 | fileprivate func getAssociatedBool(key: UnsafeRawPointer) -> Bool? {
73 | return (objc_getAssociatedObject(self, key) as? NSNumber)?.boolValue
74 | }
75 |
76 | fileprivate func setAssociatedBool(_ bool: Bool, key: UnsafeRawPointer) {
77 | objc_setAssociatedObject(self, key, NSNumber(value: bool), objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/iOS-tvOS/UIStoryboard+Swizzling.swift:
--------------------------------------------------------------------------------
1 | #if canImport(UIKit)
2 | import UIKit
3 |
4 | extension UIStoryboard {
5 | static func swizzling() {
6 | DispatchQueue.once(token: "swinject.storyboard.init") {
7 | let aClass: AnyClass = object_getClass(self)!
8 |
9 | let originalSelector = #selector(UIStoryboard.init(name:bundle:))
10 | let swizzledSelector = #selector(swinject_init(name:bundle:))
11 |
12 | let originalMethod = class_getInstanceMethod(aClass, originalSelector)!
13 | let swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector)!
14 |
15 | let didAddMethod = class_addMethod(aClass, originalSelector,
16 | method_getImplementation(swizzledMethod),
17 | method_getTypeEncoding(swizzledMethod))
18 |
19 | guard didAddMethod else {
20 | method_exchangeImplementations(originalMethod, swizzledMethod)
21 | return
22 | }
23 | class_replaceMethod(aClass, swizzledSelector,
24 | method_getImplementation(originalMethod),
25 | method_getTypeEncoding(originalMethod))
26 | }
27 | }
28 |
29 | @objc class func swinject_init(name: String, bundle: Bundle?) -> UIStoryboard {
30 | guard self == UIStoryboard.self else {
31 | return self.swinject_init(name: name, bundle: bundle)
32 | }
33 | // Instantiate SwinjectStoryboard if UIStoryboard is trying to be instantiated.
34 | if SwinjectStoryboard.isCreatingStoryboardReference {
35 | return SwinjectStoryboard.createReferenced(name: name, bundle: bundle)
36 | } else {
37 | return SwinjectStoryboard.create(name: name, bundle: bundle)
38 | }
39 | }
40 | }
41 | #endif
42 |
--------------------------------------------------------------------------------
/Sources/iOS-tvOS/_SwinjectStoryboardBase(iOS-tvOS).swift:
--------------------------------------------------------------------------------
1 | #if canImport(UIKit)
2 | import UIKit
3 | import Swinject
4 |
5 | @objcMembers
6 | public class _SwinjectStoryboardBase: UIStoryboard {
7 | public class func _create(_ name: String, bundle storyboardBundleOrNil: Bundle?) -> Self {
8 | let storyboard = perform(#selector(UIStoryboard.init(name:bundle:)), with: name, with: storyboardBundleOrNil)?
9 | .takeUnretainedValue()
10 | return storyboard as! Self
11 | }
12 | }
13 |
14 | extension SwinjectStoryboard {
15 | @objc public static func configure() {
16 | UIStoryboard.swizzling()
17 | DispatchQueue.once(token: "swinject.storyboard.setup") {
18 | guard SwinjectStoryboard.responds(to: _Selector("setup")) else { return }
19 | SwinjectStoryboard.perform(_Selector("setup"))
20 | }
21 | }
22 |
23 | static func _Selector(_ str: String) -> Selector {
24 | return Selector(str)
25 | }
26 | }
27 | #endif
28 |
--------------------------------------------------------------------------------
/SwinjectStoryboard.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "SwinjectStoryboard"
3 | s.version = "2.2.3"
4 | s.summary = "Swinject extension for automatic dependency injection via Storyboard"
5 | s.description = <<-DESC
6 | SwinjectStoryboard is an extension of Swinject to automatically inject dependency to view controllers instantiated by a storyboard.
7 | DESC
8 | s.homepage = "https://github.com/Swinject/SwinjectStoryboard"
9 | s.license = 'MIT'
10 | s.author = 'Swinject Contributors'
11 | s.source = { :git => "https://github.com/Swinject/SwinjectStoryboard.git", :tag => s.version.to_s }
12 |
13 | objc_files = 'Sources/ObjectiveC/Others/*.{swift,m,h}'
14 | core_files = 'Sources/*.{swift,m,h}'
15 | s.swift_versions = '5.0'
16 | s.ios.source_files = core_files, objc_files, 'Sources/iOS-tvOS/*.{swift,h,m}'
17 | s.osx.source_files = core_files, objc_files, 'Sources/OSX/*.{swift,h,m}'
18 | s.tvos.source_files = core_files, objc_files, 'Sources/iOS-tvOS/*.{swift,h,m}'
19 | s.ios.deployment_target = '8.0'
20 | s.osx.deployment_target = '10.10'
21 | s.tvos.deployment_target = '9.0'
22 | s.dependency 'Swinject', '~> 2.7'
23 | s.requires_arc = true
24 | end
25 |
--------------------------------------------------------------------------------
/SwinjectStoryboard.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwinjectStoryboard.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwinjectStoryboard.xcodeproj/xcshareddata/xcschemes/SwinjectStoryboard-OSX.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
51 |
52 |
62 |
63 |
69 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
88 |
90 |
91 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/SwinjectStoryboard.xcodeproj/xcshareddata/xcschemes/SwinjectStoryboard-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
51 |
52 |
62 |
63 |
69 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
88 |
90 |
91 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/SwinjectStoryboard.xcodeproj/xcshareddata/xcschemes/SwinjectStoryboard-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
51 |
52 |
62 |
63 |
69 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
88 |
90 |
91 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/Tests/Animal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Animal.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 7/27/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | internal protocol Animal {
12 | var name: String? { get set }
13 | }
14 |
15 | internal class Cat: Animal {
16 | var name: String?
17 | var sleeping = false
18 | var favoriteFood: Food?
19 |
20 | init() {
21 | }
22 |
23 | init(name: String) {
24 | self.name = name
25 | }
26 |
27 | init(name: String, sleeping: Bool) {
28 | self.name = name
29 | self.sleeping = sleeping
30 | }
31 | }
32 |
33 | internal class Siamese: Cat {
34 | }
35 |
36 | internal class Dog: Animal {
37 | var name: String?
38 |
39 | init() {
40 | }
41 |
42 | init(name: String) {
43 | self.name = name
44 | }
45 | }
46 |
47 | internal struct Turtle: Animal {
48 | var name: String?
49 | }
50 |
--------------------------------------------------------------------------------
/Tests/Container+SwinjectStoryboardTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Container+SwinjectStoryboardTests.swift
3 | // SwinjectStoryboard
4 | //
5 | // Created by Yoichi Tagaya on 2021/07/03.
6 | // Copyright © 2021 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import Swinject
11 |
12 | #if os(iOS) || os(OSX) || os(tvOS)
13 |
14 | class Container_SwinjectStoryboardTests: XCTestCase {
15 | func testCustomStringConvertibleDescribesRegistrationWithStoryboardOption() {
16 | let container = Container()
17 | let controllerType = String(describing: Container.Controller.self) // "UIViewController" for iOS/tvOS, "AnyObject" for OSX.
18 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in }
19 |
20 | let expected = "[\n"
21 | + " { Service: \(controllerType), Storyboard: SwinjectStoryboardTests.AnimalViewController, "
22 | + "Factory: (Resolver, \(controllerType)) -> \(controllerType), ObjectScope: graph, InitCompleted: Specified 1 closures }\n"
23 | + "]"
24 | XCTAssertEqual(container.description, expected)
25 | }
26 | }
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/Tests/Food.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Food.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 7/29/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | internal protocol Food { }
12 |
13 | internal class Sushi: Food { }
14 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 2.2.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Tests/NSWindowController+SwinjectTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSWindowController+SwinjectTests.swift
3 | // SwinjectStoryboard
4 | //
5 | // Created by Yoichi Tagaya on 2021/07/03.
6 | // Copyright © 2021 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | #if os(OSX)
10 |
11 | import XCTest
12 | @testable import SwinjectStoryboard
13 |
14 | class NSWindowController_SwinjectTests: XCTestCase {
15 | func testPropertyToStoreSwinjectContainerRegistrationName() {
16 | let controller1 = NSWindowController(window: nil)
17 | let controller2 = NSWindowController(window: nil)
18 | controller1.swinjectRegistrationName = "1"
19 | controller2.swinjectRegistrationName = "2"
20 |
21 | XCTAssertEqual(controller1.swinjectRegistrationName, "1")
22 | XCTAssertEqual(controller2.swinjectRegistrationName, "2")
23 | }
24 | }
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/Tests/OSX/AnimalPagesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimalPagesViewController.swift
3 | // Swinject
4 | //
5 | // Created by Jakub Vaňo on 27/10/16.
6 | // Copyright © 2016 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import AppKit
10 | import Swinject
11 |
12 | internal class AnimalPagesViewController: NSPageController {
13 | let animalPage: AnimalViewController
14 |
15 | required init?(coder aDecoder: NSCoder) {
16 | animalPage = NSStoryboard(
17 | name: NSStoryboard.Name("Pages"),
18 | bundle: Bundle(for: AnimalPagesViewController.self)
19 | ).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("AnimalPage")) as! AnimalViewController
20 |
21 | super.init(coder: aDecoder)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tests/OSX/AnimalViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimalViewController.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 8/1/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import AppKit
10 |
11 | internal class AnimalViewController: NSViewController {
12 | internal var animal: Animal?
13 |
14 | internal required init?(coder: NSCoder) {
15 | super.init(coder: coder)
16 | }
17 |
18 | internal func hasAnimal(named name: String) -> Bool {
19 | return animal?.name == name
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/OSX/AnimalWindowController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimalWindowController.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 8/1/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import AppKit
10 |
11 | internal class AnimalWindowController: NSWindowController {
12 | internal var animal: Animal?
13 |
14 | internal required init?(coder: NSCoder) {
15 | super.init(coder: coder)
16 | }
17 |
18 | internal func hasAnimal(named name: String) -> Bool {
19 | return animal?.name == name
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/OSX/Animals.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Tests/OSX/Pages.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Tests/OSX/RelationshipReference1.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Tests/OSX/RelationshipReference2.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Tests/OSX/Storyboard1.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Tests/OSX/Storyboard2.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/OSX/SwinjectStoryboardTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwinjectStoryboardTests.swift
3 | // SwinjectStoryboard-OSXTests
4 | //
5 | // Created by Yoichi Tagaya on 2021/07/03.
6 | // Copyright © 2021 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import Swinject
11 | @testable import SwinjectStoryboard
12 |
13 | private var swinjectStoryboardSetupCount = 0
14 | extension SwinjectStoryboard {
15 | static func setup() {
16 | swinjectStoryboardSetupCount += 1
17 | }
18 | }
19 |
20 | class SwinjectStoryboardTests: XCTestCase {
21 | let bundle = Bundle(for: SwinjectStoryboardTests.self)
22 | var container: Container!
23 |
24 | override func setUpWithError() throws {
25 | container = Container()
26 | }
27 |
28 | // MARK: Instantiation from storyboard
29 | func testSwinjectStoryboardInjectsViewControllerDependencyDefindedByInitCompletedHandler() {
30 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
31 | c.animal = r.resolve(Animal.self)
32 | }
33 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
34 |
35 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle, container: container)
36 | let animalViewController = storyboard.instantiateController(withIdentifier: .animalView) as! AnimalViewController
37 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
38 | }
39 |
40 | func testSwinjectStoryboardInjectsWindowControllerDependencyDefindedByInitCompletedHandler() {
41 | container.storyboardInitCompleted(AnimalWindowController.self) { r, c in
42 | c.animal = r.resolve(Animal.self)
43 | }
44 | container.register(Animal.self) { _ in Cat(name: "Mew") }
45 |
46 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle, container: container)
47 | let animalViewController = storyboard.instantiateController(withIdentifier: .animalWindow) as! AnimalWindowController
48 | XCTAssert(animalViewController.hasAnimal(named: "Mew"))
49 | }
50 |
51 | func testSwinjectStoryboardInjectsDependencyToChildViewControllers() {
52 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
53 | c.animal = r.resolve(Animal.self)
54 | }
55 | container.register(Animal.self) { _ in Cat() }
56 | .inObjectScope(.container)
57 |
58 | let storyboard = SwinjectStoryboard.create(name: .tabs, bundle: bundle, container: container)
59 | let tabBarController = storyboard.instantiateController(withIdentifier: .tabBarController) as! NSTabViewController
60 | #if swift(>=4.2)
61 | let animalViewController1 = tabBarController.children[0] as! AnimalViewController
62 | let animalViewController2 = tabBarController.children[1] as! AnimalViewController
63 | #else
64 | let animalViewController1 = tabBarController.childViewControllers[0] as! AnimalViewController
65 | let animalViewController2 = tabBarController.childViewControllers[1] as! AnimalViewController
66 | #endif
67 | let cat1 = animalViewController1.animal as! Cat
68 | let cat2 = animalViewController2.animal as! Cat
69 | XCTAssert(cat1 === cat2)
70 | }
71 |
72 | func testSwinjectStoryboardInjectsViewContrllerDependencyDefindedByInitCompletedHandlerWithRegistrationNameAsUserDefinedRuntimeAttributeOnInterfaceBuilder() {
73 | // The registration name "hachi" is set in the storyboard.
74 | container.storyboardInitCompleted(AnimalViewController.self, name: "hachi") { r, c in
75 | c.animal = r.resolve(Animal.self)
76 | }
77 | container.register(Animal.self) { _ in Dog(name: "Hachi") }
78 |
79 | // This registration should not be resolved.
80 | container.storyboardInitCompleted(AnimalViewController.self) { _, c in
81 | c.animal = Cat(name: "Mimi")
82 | }
83 |
84 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle, container: container)
85 | let animalViewController = storyboard.instantiateController(withIdentifier: .hachiView) as! AnimalViewController
86 | XCTAssert(animalViewController.hasAnimal(named: "Hachi"))
87 | }
88 |
89 | func testSwinjectStoryboardInjectsWindowContrllerDependencyDefindedByInitCompletedHandlerWithRegistrationNameAsUserDefinedRuntimeAttributeOnInterfaceBuilder() {
90 | // The registration name "hachi" is set in the storyboard.
91 | container.storyboardInitCompleted(AnimalWindowController.self, name: "pochi") { r, c in
92 | c.animal = r.resolve(Animal.self)
93 | }
94 | container.register(Animal.self) { _ in Dog(name: "Pochi") }
95 |
96 | // This registration should not be resolved.
97 | container.storyboardInitCompleted(AnimalWindowController.self) { _, c in
98 | c.animal = Cat(name: "Mimi")
99 | }
100 |
101 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle, container: container)
102 | let animalViewController = storyboard.instantiateController(withIdentifier: .pochiWindow) as! AnimalWindowController
103 | XCTAssert(animalViewController.hasAnimal(named: "Pochi"))
104 | }
105 |
106 | func testSwinjectStoryboardInjectsViewControllerDependencyDefindedInParentContainerWithContainerHierarchy() {
107 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
108 | c.animal = r.resolve(Animal.self)
109 | }
110 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
111 | let childContainer = Container(parent: container)
112 |
113 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle, container: childContainer)
114 | let animalViewController = storyboard.instantiateController(withIdentifier: .animalView) as! AnimalViewController
115 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
116 | }
117 |
118 | func testSwinjectStoryboardInjectsSecondControllerWithSecondControllerInstantiationDuringInstantiationOfInitialOne() {
119 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
120 | c.animal = r.resolve(Animal.self)
121 | }
122 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
123 |
124 | let storyboard = SwinjectStoryboard.create(name: .pages, bundle: bundle, container: container)
125 | let pagesController = storyboard.instantiateInitialController() as! AnimalPagesViewController
126 | XCTAssert(pagesController.animalPage.hasAnimal(named: "Mimi"))
127 | }
128 |
129 | // MARK: Initial controller
130 | func testInitialViewControllerInjectsDependencyDefindedByInitCompletedHandler() {
131 | container.storyboardInitCompleted(AnimalWindowController.self) { r, c in
132 | c.animal = r.resolve(Animal.self)
133 | }
134 | container.register(Animal.self) { _ in Cat(name: "Mew") }
135 |
136 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle, container: container)
137 | let animalViewController = storyboard.instantiateInitialController() as! AnimalWindowController
138 | XCTAssert(animalViewController.hasAnimal(named: "Mew"))
139 | }
140 |
141 | // MARK: Factory method
142 | func testFactoryMethodUsesDefaultSharedContainerIfNoContainerIsPassed() {
143 | SwinjectStoryboard.defaultContainer.storyboardInitCompleted(AnimalViewController.self) { _, _ in }
144 | defer {
145 | SwinjectStoryboard.defaultContainer.removeAll()
146 | }
147 |
148 | let storyboard = SwinjectStoryboard.create(name: .animals, bundle: bundle)
149 | let animalViewController = storyboard.instantiateController(withIdentifier: .animalView)
150 | XCTAssertNotNil(animalViewController)
151 | }
152 |
153 | // MARK: Storyboard reference
154 | func testStoryboardReferenceInjectsDependencyToViewControllerInReferencedStoryboard() {
155 | SwinjectStoryboard.defaultContainer.storyboardInitCompleted(AnimalViewController.self) { r, c in
156 | c.animal = r.resolve(Animal.self)
157 | }
158 | SwinjectStoryboard.defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
159 | defer {
160 | SwinjectStoryboard.defaultContainer.removeAll()
161 | }
162 |
163 | let storyboard1 = SwinjectStoryboard.create(name: .storyboard1, bundle: bundle)
164 | let windowController = storyboard1.instantiateInitialController() as! NSWindowController
165 | let viewController1 = windowController.contentViewController as! ViewController1
166 | viewController1.performSegue(withIdentifier: .toStoryboard2, sender: nil)
167 |
168 | assertEventually {
169 | viewController1.animalViewController?.hasAnimal(named: "Mimi") == true
170 | }
171 | }
172 |
173 | func testStoryboardReferenceShouldInjectDependenciesOnceIfReferencingStoryboardViaRelationshipSegue() {
174 | var injectedTimes = 0
175 | SwinjectStoryboard.defaultContainer.storyboardInitCompleted(ViewController1.self) { r, c in
176 | injectedTimes += 1
177 | }
178 | defer {
179 | SwinjectStoryboard.defaultContainer.removeAll()
180 | }
181 |
182 | let storyboard = SwinjectStoryboard.create(name: .relationshipReference1, bundle: bundle)
183 | storyboard.instantiateInitialController()
184 |
185 | XCTAssertEqual(injectedTimes, 1)
186 | }
187 |
188 | func testStoryboardReferenceInjectsDependencyToViewControllerpenedViaSegueIfNotUsingDefaultContainer() {
189 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
190 | c.animal = r.resolve(Animal.self)
191 | }
192 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
193 |
194 | let storyboard = SwinjectStoryboard.create(name: .relationshipReference1, bundle: bundle, container: container)
195 | let windowController = storyboard.instantiateInitialController() as! NSWindowController
196 | let viewController1 = windowController.contentViewController as! ViewController1
197 | viewController1.performSegue(withIdentifier: .toAnimalViewController, sender: nil)
198 |
199 | assertEventually {
200 | viewController1.animalViewController?.hasAnimal(named: "Mimi") == true
201 | }
202 | }
203 |
204 | // MARK: Setup
205 | func testSetupIsCalledOnlyOnce() {
206 | _ = SwinjectStoryboard.create(name: .animals, bundle: bundle)
207 | _ = SwinjectStoryboard.create(name: .animals, bundle: bundle)
208 | XCTAssertEqual(swinjectStoryboardSetupCount, 1)
209 | }
210 | }
211 |
212 | private extension NSStoryboard.Name {
213 | static let animals = NSStoryboard.Name("Animals")
214 | static let storyboard1 = NSStoryboard.Name("Storyboard1")
215 | static let relationshipReference1 = NSStoryboard.Name("RelationshipReference1")
216 | static let pages = NSStoryboard.Name("Pages")
217 | static let tabs = NSStoryboard.Name("Tabs")
218 | }
219 |
220 | private extension NSStoryboard.SceneIdentifier {
221 | static let animalView = NSStoryboard.SceneIdentifier("AnimalView")
222 | static let animalWindow = NSStoryboard.SceneIdentifier("AnimalWindow")
223 | static let tabBarController = NSStoryboard.SceneIdentifier("TabBarController")
224 | static let hachiView = NSStoryboard.SceneIdentifier("HachiView")
225 | static let pochiWindow = NSStoryboard.SceneIdentifier("PochiWindow")
226 | }
227 |
228 | private extension NSStoryboardSegue.Identifier {
229 | static let toStoryboard2 = NSStoryboardSegue.Identifier("ToStoryboard2")
230 | static let toAnimalViewController = NSStoryboardSegue.Identifier("ToAnimalViewController")
231 | }
232 |
233 | // Similar to toEventually of Nimble.
234 | private func assertEventually(expression: @escaping () -> Bool) {
235 | let expectation = XCTestExpectation()
236 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
237 | XCTAssert(expression())
238 | expectation.fulfill()
239 | }
240 | XCTWaiter().wait(for: [expectation], timeout: 1.0)
241 | }
242 |
--------------------------------------------------------------------------------
/Tests/OSX/Tabs.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Tests/OSX/ViewController1.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController1.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 11/2/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ViewController1: NSViewController {
12 | var animalViewController: AnimalViewController?
13 |
14 | override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
15 | super.prepare(for: segue, sender: sender)
16 | self.animalViewController = segue.destinationController as? AnimalViewController
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/Storyboard+SwizzlingTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Storyboard+SwizzlingTests.swift
3 | // SwinjectStoryboard
4 | //
5 | // Created by Yoichi Tagaya on 2021/07/03.
6 | // Copyright © 2021 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwinjectStoryboard
11 |
12 | #if os(iOS) || os(tvOS)
13 | private typealias Storyboard = UIStoryboard
14 | private typealias Name = String
15 | #elseif os(OSX)
16 | private typealias Storyboard = NSStoryboard
17 | private typealias Name = NSStoryboard.Name
18 | #endif
19 |
20 | #if os(iOS) || os(OSX) || os(tvOS)
21 |
22 | class Storyboard_SwizzlingTests: XCTestCase {
23 | let bundle = Bundle(for: Storyboard_SwizzlingTests.self)
24 |
25 | func testSwinjectStoryboardIsInstantiatedWhenStoryboardIsTriedToBeInstantiated() {
26 | let storyboard = Storyboard(name: Name("Animals"), bundle: bundle)
27 | XCTAssert(storyboard is SwinjectStoryboard)
28 | }
29 |
30 | func testSwinjectStoryboardDoesNotHaveInfinitCallsOfSwizzledMethodWhenExplicitlyInstantiated() {
31 | let storyboard = SwinjectStoryboard.create(name: Name("Animals"), bundle: bundle)
32 | XCTAssertNotNil(storyboard)
33 | }
34 | }
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/Tests/ViewController+SwinjectTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController+SwinjectTests.swift
3 | // SwinjectStoryboard
4 | //
5 | // Created by Yoichi Tagaya on 2021/07/03.
6 | // Copyright © 2021 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwinjectStoryboard
11 |
12 | #if os(iOS) || os(tvOS)
13 | private let createViewController = { UIViewController(nibName: nil, bundle: nil) }
14 | #elseif os(OSX)
15 | private let createViewController = { NSViewController(nibName: nil, bundle: nil) }
16 | #endif
17 |
18 | #if os(iOS) || os(OSX) || os(tvOS)
19 |
20 | class ViewController_SwinjectTests: XCTestCase {
21 |
22 | func testPropertyToStoreSwinjectContainerRegistrationName() {
23 | let viewController1 = createViewController()
24 | let viewController2 = createViewController()
25 | viewController1.swinjectRegistrationName = "1"
26 | viewController2.swinjectRegistrationName = "2"
27 |
28 | XCTAssertEqual(viewController1.swinjectRegistrationName, "1")
29 | XCTAssertEqual(viewController2.swinjectRegistrationName, "2")
30 | }
31 | }
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/AnimalPagesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimalPagesViewController.swift
3 | // Swinject
4 | //
5 | // Created by Jakub Vaňo on 27/10/16.
6 | // Copyright © 2016 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Swinject
11 |
12 | internal class AnimalPagesViewController: UIPageViewController {
13 | let animalPage: AnimalViewController
14 |
15 | required init?(coder aDecoder: NSCoder) {
16 | animalPage = UIStoryboard(
17 | name: "Pages",
18 | bundle: Bundle(for: AnimalPagesViewController.self)
19 | ).instantiateViewController(withIdentifier: "AnimalPage") as! AnimalViewController
20 |
21 | super.init(coder: aDecoder)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/AnimalPlayerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimalPlayerViewController.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 11/1/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import AVKit
10 |
11 | internal class AnimalPlayerViewController: AVPlayerViewController {
12 | internal var animal: Animal?
13 |
14 | internal required init?(coder aDecoder: NSCoder) {
15 | super.init(coder: aDecoder)
16 | }
17 |
18 | internal func hasAnimal(named name: String) -> Bool {
19 | return animal?.name == name
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/AnimalViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimalViewController.swift
3 | // Swinject
4 | //
5 | // Created by Yoichi Tagaya on 7/31/15.
6 | // Copyright © 2015 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal class AnimalViewController: UIViewController {
12 | internal var animal: Animal?
13 |
14 | internal required init?(coder aDecoder: NSCoder) {
15 | super.init(coder: aDecoder)
16 | }
17 |
18 | internal func hasAnimal(named name: String) -> Bool {
19 | return animal?.name == name
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/AnimalPlayerViewController.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/Animals.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/Pages.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/RelationshipReference1.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/RelationshipReference2.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/Storyboard1.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/Storyboard2.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/iOS/Tabs.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/AnimalPlayerViewController.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/Animals.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/Pages.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/RelationshipReference1.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/RelationshipReference2.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/Storyboard1.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/Storyboard2.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/Storyboards/tvOS/Tabs.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Tests/iOS-tvOS/SwinjectStoryboardTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwinjectStoryboardTests.swift
3 | // SwinjectStoryboard
4 | //
5 | // Created by Yoichi Tagaya on 2021/07/03.
6 | // Copyright © 2021 Swinject Contributors. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import Swinject
11 | @testable import SwinjectStoryboard
12 |
13 | private var swinjectStoryboardSetupCount = 0
14 | extension SwinjectStoryboard {
15 | static func setup() {
16 | swinjectStoryboardSetupCount += 1
17 | }
18 | }
19 |
20 | class SwinjectStoryboardTests: XCTestCase {
21 | let bundle = Bundle(for: SwinjectStoryboardTests.self)
22 | var container: Container!
23 |
24 | override func setUpWithError() throws {
25 | container = Container()
26 | }
27 |
28 | // MARK: Instantiation from storyboard
29 | func testSwinjectStoryboardInjectsDependencyDefindedByInitCompletedHandler() {
30 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
31 | c.animal = r.resolve(Animal.self)
32 | }
33 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
34 |
35 | let storyboard = SwinjectStoryboard.create(name: "Animals", bundle: bundle, container: container)
36 | let animalViewController = storyboard.instantiateViewController(withIdentifier: "AnimalAsCat") as! AnimalViewController
37 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
38 | }
39 |
40 | func testSwinjectStoryboardInjectsDependencyToChildViewControllers() {
41 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
42 | c.animal = r.resolve(Animal.self)
43 | }
44 | container.register(Animal.self) { _ in Cat() }
45 | .inObjectScope(.container)
46 |
47 | let storyboard = SwinjectStoryboard.create(name: "Tabs", bundle: bundle, container: container)
48 | let tabBarController = storyboard.instantiateViewController(withIdentifier: "TabBarController")
49 | #if swift(>=4.2)
50 | let animalViewController1 = tabBarController.children[0] as! AnimalViewController
51 | let animalViewController2 = tabBarController.children[1] as! AnimalViewController
52 | #else
53 | let animalViewController1 = tabBarController.childViewControllers[0] as! AnimalViewController
54 | let animalViewController2 = tabBarController.childViewControllers[1] as! AnimalViewController
55 | #endif
56 | let cat1 = animalViewController1.animal as! Cat
57 | let cat2 = animalViewController2.animal as! Cat
58 | XCTAssert(cat1 === cat2)
59 | }
60 |
61 | func testSwinjectStoryboardInjectsDependencyDefindedByInitCompletedHandlerWithRegistrationNameAsUserDefinedRuntimeAttributeOnInterfaceBuilder() {
62 | // The registration name "hachi" is set in the storyboard.
63 | container.storyboardInitCompleted(AnimalViewController.self, name: "hachi") { r, c in
64 | c.animal = r.resolve(Animal.self)
65 | }
66 | container.register(Animal.self) { _ in Dog(name: "Hachi") }
67 |
68 | // This registration should not be resolved.
69 | container.storyboardInitCompleted(AnimalViewController.self) { _, c in
70 | c.animal = Cat(name: "Mimi")
71 | }
72 |
73 | let storyboard = SwinjectStoryboard.create(name: "Animals", bundle: bundle, container: container)
74 | let animalViewController = storyboard.instantiateViewController(withIdentifier: "AnimalAsDog") as! AnimalViewController
75 | XCTAssert(animalViewController.hasAnimal(named: "Hachi"))
76 | }
77 |
78 | func testSwinjectStoryboardInjectsViewControllerDependencyDefindedInParentContainerWithContainerHierarchy() {
79 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
80 | c.animal = r.resolve(Animal.self)
81 | }
82 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
83 | let childContainer = Container(parent: container)
84 |
85 | let storyboard = SwinjectStoryboard.create(name: "Animals", bundle: bundle, container: childContainer)
86 | let animalViewController = storyboard.instantiateViewController(withIdentifier: "AnimalAsCat") as! AnimalViewController
87 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
88 | }
89 |
90 | func testSwinjectStoryboardInjectsSecondControllerWithSecondControllerInstantiationDuringInstantiationOfInitialOne() {
91 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
92 | c.animal = r.resolve(Animal.self)
93 | }
94 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
95 |
96 | let storyboard = SwinjectStoryboard.create(name: "Pages", bundle: bundle, container: container)
97 | let pagesController = storyboard.instantiateInitialViewController() as! AnimalPagesViewController
98 | XCTAssert(pagesController.animalPage.hasAnimal(named: "Mimi"))
99 | }
100 |
101 | // MARK: Initial view controller
102 | func testInitialViewControllerInjectsDependencyDefindedByInitCompletedHandler() {
103 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
104 | c.animal = r.resolve(Animal.self)
105 | }
106 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
107 |
108 | let storyboard = SwinjectStoryboard.create(name: "Animals", bundle: bundle, container: container)
109 | let animalViewController = storyboard.instantiateInitialViewController() as! AnimalViewController
110 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
111 | }
112 |
113 | // MARK: AVPlayerViewController
114 | // Test for Issue #18
115 | func testAVPlayerViewControllerIsAbleToInjectSubclassOfAVPlayerViewController() {
116 | container.storyboardInitCompleted(AnimalPlayerViewController.self) { r, c in
117 | c.animal = r.resolve(Animal.self)
118 | }
119 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
120 |
121 | let storyboard = SwinjectStoryboard.create(name: "AnimalPlayerViewController", bundle: bundle, container: container)
122 | let animalPlayerViewController = storyboard.instantiateInitialViewController() as! AnimalPlayerViewController
123 | XCTAssert(animalPlayerViewController.hasAnimal(named: "Mimi"))
124 | }
125 |
126 | // MARK: Factory method
127 | func testFactoryMethodUsesDefaultSharedContainerIfNoContainerIsPassed() {
128 | SwinjectStoryboard.defaultContainer.storyboardInitCompleted(AnimalViewController.self) { _, _ in }
129 | defer {
130 | SwinjectStoryboard.defaultContainer.removeAll()
131 | }
132 |
133 | let storyboard = SwinjectStoryboard.create(name: "Animals", bundle: bundle)
134 | let animalViewController = storyboard.instantiateViewController(withIdentifier: "AnimalAsCat")
135 | XCTAssertNotNil(animalViewController)
136 | }
137 |
138 | // MARK: Storyboard reference
139 | func testStoryboardReferenceInjectsDependencyToViewControllerInReferencedStoryboard() {
140 | SwinjectStoryboard.defaultContainer.storyboardInitCompleted(AnimalViewController.self) { r, c in
141 | c.animal = r.resolve(Animal.self)
142 | }
143 | SwinjectStoryboard.defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
144 | defer {
145 | SwinjectStoryboard.defaultContainer.removeAll()
146 | }
147 |
148 | let storyboard1 = SwinjectStoryboard.create(name: "Storyboard1", bundle: bundle)
149 | let navigationController = storyboard1.instantiateInitialViewController() as! UINavigationController
150 | navigationController.performSegue(withIdentifier: "ToStoryboard2", sender: navigationController)
151 | let animalViewController = navigationController.topViewController as! AnimalViewController
152 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
153 | }
154 |
155 | func testStoryboardReferenceShouldInjectDependenciesOnceIfReferencingStoryboardViaRelationshipSegue() {
156 | var injectedTimes = 0
157 | SwinjectStoryboard.defaultContainer.storyboardInitCompleted(UIViewController.self) { r, c in
158 | injectedTimes += 1
159 | }
160 | defer {
161 | SwinjectStoryboard.defaultContainer.removeAll()
162 | }
163 |
164 | let storyboard = SwinjectStoryboard.create(name: "RelationshipReference1", bundle: bundle)
165 | storyboard.instantiateInitialViewController()
166 |
167 | XCTAssertEqual(injectedTimes, 1)
168 | }
169 |
170 | func testStoryboardReferenceInjectsDependencyToViewControllerpenedViaSegueIfNotUsingDefaultContainer() {
171 | container.storyboardInitCompleted(AnimalViewController.self) { r, c in
172 | c.animal = r.resolve(Animal.self)
173 | }
174 | container.register(Animal.self) { _ in Cat(name: "Mimi") }
175 |
176 | let storyboard = SwinjectStoryboard.create(name: "RelationshipReference1", bundle: bundle, container: container)
177 | let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController
178 | navigationController.topViewController!.performSegue(withIdentifier: "ToAnimalViewController", sender: nil)
179 | let animalViewController = navigationController.topViewController as! AnimalViewController
180 |
181 | XCTAssert(animalViewController.hasAnimal(named: "Mimi"))
182 | }
183 |
184 | // MARK: Setup
185 | func testSetupIsCalledOnlyOnce() {
186 | _ = SwinjectStoryboard.create(name: "Animals", bundle: bundle)
187 | _ = SwinjectStoryboard.create(name: "Animals", bundle: bundle)
188 | XCTAssertEqual(swinjectStoryboardSetupCount, 1)
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/carthage-build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # carthage.sh
4 | # Usage example: ./carthage-build.sh build --platform iOS
5 |
6 | set -euo pipefail
7 |
8 | xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
9 | trap 'rm -f "$xcconfig"' INT TERM HUP EXIT
10 |
11 | # For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise
12 | # the build will fail on lipo due to duplicate architectures.
13 | echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = arm64 arm64e armv7 armv7s armv6 armv8' >> $xcconfig
14 | echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig
15 |
16 | export XCODE_XCCONFIG_FILE="$xcconfig"
17 | carthage "$@"
--------------------------------------------------------------------------------