Compare commits

...

29 Commits

Author SHA1 Message Date
Olivier Halligon 7f9c54e484 Version Bump: 2.0.0 2015-10-31 15:21:48 +01:00
Olivier Halligon ec177fba78 Rearranged classes in Dip.swift
To make Tag and LookupKey (formerly ProtoTypeKey) inner classes of DependencyContainer
2015-10-31 15:17:25 +01:00
AliSoftware 6b6f85ba4c Merge pull request #3 from ilyapuchka/master
Remove DependencyContainer Generic constraints

See rationale in PR #3
2015-10-31 14:52:41 +01:00
Ilya Puchka 5f845e6701 updated change log 2015-10-30 23:19:15 +01:00
Ilya Puchka 0028083289 updated sample app 2015-10-30 15:30:17 +01:00
Ilya Puchka 10dd5a51a5 Updated readme 2015-10-29 19:50:26 +01:00
Ilya Puchka 4e3a53997e added support for string and integer literal convertible protocols 2015-10-29 19:50:25 +01:00
Ilya Puchka ae8d56e5d8 tag implemented as enum with String and Int cases 2015-10-29 17:01:58 +01:00
Ilya Puchka bc303da493 changed tag back to String 2015-10-23 23:55:44 +02:00
Ilya Puchka 0db3155835 Removed unneeded Any generic constraint 2015-10-23 23:02:18 +02:00
Olivier Halligon 74112c6051 Yummy animated GIF in README ;) 2015-10-11 17:27:41 +02:00
Olivier Halligon a98a9eed56 [README] Using local GIF + Fixing links to source code from the README 2015-10-11 16:25:23 +02:00
Olivier Halligon a4f6db4f8d Bump Version to 1.0.1 — Improved README and Discoverability 2015-10-11 16:11:54 +02:00
Olivier Halligon a74b527324 Better README 2015-10-11 15:43:51 +02:00
Olivier Halligon 225fb70bd4 Version bump: 1.0.0 2015-10-11 15:16:55 +02:00
Olivier Halligon 368d4f920f SWAPIStarshipProviderTests 2015-10-11 15:01:31 +02:00
Olivier Halligon 61042efb53 SWAPIPersonProviderTests 2015-10-11 14:26:39 +02:00
Olivier Halligon 4ba6e48fd2 Convert var fetchIDs and fetchOne to functions for readability
+ some code formatting fixes
2015-10-11 05:09:15 +02:00
Olivier Halligon 2303aee66f Bump to 0.1.0 2015-10-11 03:49:55 +02:00
Olivier Halligon 7dd3fc3c5c Source Documentation 2015-10-11 03:39:33 +02:00
Olivier Halligon c920c4f425 Thread Safety 2015-10-11 03:37:00 +02:00
Olivier Halligon c0833fd92f Addie ability to init with a block that allows to register dependencies directly 2015-10-11 02:57:56 +02:00
Olivier Halligon 31673bbf21 Cleanup + fix missing values in HardCoded Provider 2015-10-11 02:48:16 +02:00
Olivier Halligon 219e7fd5c1 Added SWAPIProviders that implement the swapi.co WS 2015-10-11 00:44:44 +02:00
Olivier Halligon 6085ce5f21 Use specific providers for some IDs to demonstrate the resolve(tag) usage
Also changed the XProviderAPIs to return a list of IDs instead of directly a list of object. This way we can use a provider to retrieve the IDs first and another to retrieve the Person from its ID which plays better with the demo
2015-10-10 21:36:35 +02:00
Olivier Halligon 3bca744c82 separate the FillableCell protocol requirements from the BaseCell protocol 2015-10-10 18:20:31 +02:00
Olivier Halligon c311eea591 Lazy vars for fetchOne/fetchAll 2015-10-09 04:23:15 +02:00
Olivier Halligon 120a98b157 Using the Mixins & Traits tip to factorize FetchableTrait between the two ViewControllers 2015-10-09 03:53:00 +02:00
Olivier Halligon 937709fba2 Completely changed the Sample project for a better example 2015-10-09 02:15:49 +02:00
85 changed files with 2403 additions and 1065 deletions
+1
View File
@@ -13,6 +13,7 @@ build/
!default.perspectivev3
xcuserdata
*.xccheckout
*.xcscmblueprint
profile
*.moved-aside
DerivedData
+61
View File
@@ -1,7 +1,68 @@
# CHANGELOG
## 2.0.0
* Moved from generic _tag_ parameter on container to `Tag` enum with `String` and `Int` cases
[#3](https://github.com/AliSoftware/Dip/pull/3), [@ilyapuchka](https://github.com/ilyapuchka)
> This API change allows easier use of `DependencyContainer` and avoid some constraints. For a complete rationale on that change, see [PR #3](https://github.com/AliSoftware/Dip/pull/3).
## 1.0.1
* Improved README
* Imrpoved discoverability using keywords in `podspec`
## 1.0.0
#### Dip
* Added Unit Tests for `SWAPIPersonProvider` and `SWAPIStarshipProvider`
_All work in progress is now done. I consider `Dip` to be ready for production and with a stable API, hence the `1.0.0` version bump._
#### Example Project
* Using `func fetchIDs` and `func fetchOne` instead of `lazy var` for readability
## 0.1.0
#### Dip
* Dip is now Thread-Safe
* Added a configuration block so we can easily create the container and register the dependencies all in one expression:
```swift
let deps = DependencyContainer() {
$0.register() { x as Foo }
$0.register() { y as Bar }
$0.register() { z as Baz }
}
```
* Source Documentation
#### Example Project
* Code Cleanup
* Added more values to `HardCodedStarshipProvider` so it works when the `PersonProviderAPI` uses real pilots from swapi.co (`SWAPIPersonProvider`)
## 0.0.4
#### Example Project
* Added `SWAPIPersonProvider` & `SWAPIStarshipProvider` that use http://swapi.co
## 0.0.3
#### Example Project
* Revamped the Sample project to a more complete example (using StarWars API!)
* Using Mixins & Traits in the Sample App for `FetchableTrait` and `FillableCell`
## 0.0.2
#### Dip
* Switched from class methods to instance methods ([#1](https://github.com/AliSoftware/Dip/issues/1)). This allows you to have multiple `DependencyContainers`
* Renamed the class from `Dependency` to `DependencyContainer`
* Renamed the `instanceFactory:` parameter to `factory:`
+3 -5
View File
@@ -1,11 +1,11 @@
Pod::Spec.new do |s|
s.name = "Dip"
s.version = "0.0.1"
s.summary = "A simple Dependency Resolver (Simplified Dependency Injection-like resolution)."
s.version = "2.0.0"
s.summary = "A simple Dependency Resolver: Dependency Injection using Protocol resolution."
s.description = <<-DESC
Dip is a Swift framework to manage your Dependencies between your classes
in your app.
in your app using Dependency Injection.
It's aimed to be very simple to use while improving testability
of your app by allowing you to get rid of those sharedInstances and instead
@@ -15,8 +15,6 @@ Pod::Spec.new do |s|
an instance dynamically in your classes. Then your App and your Tests can be
configured to resolve the protocol using a different instance or class so this
improve testability by decoupling the API and the concrete class used to implement it.
It's not real Dependency Injection _per se_, but it's close.
DESC
s.homepage = "https://github.com/AliSoftware/Dip"
+167 -119
View File
@@ -7,68 +7,84 @@
objects = {
/* Begin PBXBuildFile section */
097D52E81BC13B0D006C893C /* WebServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E71BC13B0D006C893C /* WebServiceAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D52EA1BC15FFF006C893C /* PersonFactoryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D52ED1BC16091006C893C /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EC1BC16091006C893C /* Person.swift */; settings = {ASSET_TAGS = (); }; };
097D52EF1BC1611C006C893C /* SWAPIWebService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EE1BC1611C006C893C /* SWAPIWebService.swift */; settings = {ASSET_TAGS = (); }; };
097D52F11BC161F7006C893C /* SerializerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F01BC161F7006C893C /* SerializerAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D52F51BC166F3006C893C /* JSONSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F41BC166F3006C893C /* JSONSerializer.swift */; settings = {ASSET_TAGS = (); }; };
097D52F71BC169C0006C893C /* SWAPIPersonFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */; settings = {ASSET_TAGS = (); }; };
097D52F91BC17418006C893C /* PersonFormatterAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F81BC17418006C893C /* PersonFormatterAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D52FB1BC1745B006C893C /* MassHeightFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */; settings = {ASSET_TAGS = (); }; };
097D52FD1BC174B6006C893C /* EyesHairFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */; settings = {ASSET_TAGS = (); }; };
097D53011BC31F4A006C893C /* Tags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53001BC31F4A006C893C /* Tags.swift */; settings = {ASSET_TAGS = (); }; };
097D53021BC31FA6006C893C /* WebServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E71BC13B0D006C893C /* WebServiceAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D53031BC31FA6006C893C /* SerializerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F01BC161F7006C893C /* SerializerAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D53041BC31FA6006C893C /* PersonFactoryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D53051BC31FA6006C893C /* PersonFormatterAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F81BC17418006C893C /* PersonFormatterAPI.swift */; settings = {ASSET_TAGS = (); }; };
097D53061BC31FAE006C893C /* SWAPIWebService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EE1BC1611C006C893C /* SWAPIWebService.swift */; settings = {ASSET_TAGS = (); }; };
097D53071BC31FC5006C893C /* Tags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53001BC31F4A006C893C /* Tags.swift */; settings = {ASSET_TAGS = (); }; };
097D53081BC32053006C893C /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EC1BC16091006C893C /* Person.swift */; settings = {ASSET_TAGS = (); }; };
097D530A1BC3243D006C893C /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53091BC3243D006C893C /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
097D530C1BC324DA006C893C /* NSURLSessionNetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D530B1BC324DA006C893C /* NSURLSessionNetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
097D530D1BC3250B006C893C /* SWAPIPersonFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */; settings = {ASSET_TAGS = (); }; };
097D530E1BC3250E006C893C /* JSONSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F41BC166F3006C893C /* JSONSerializer.swift */; settings = {ASSET_TAGS = (); }; };
097D530F1BC3250E006C893C /* MassHeightFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */; settings = {ASSET_TAGS = (); }; };
097D53101BC3250E006C893C /* EyesHairFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */; settings = {ASSET_TAGS = (); }; };
097D53111BC32513006C893C /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53091BC3243D006C893C /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
090012291BC6FECA0079C600 /* BaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090012161BC6FECA0079C600 /* BaseCell.swift */; settings = {ASSET_TAGS = (); }; };
0900122A1BC6FECA0079C600 /* PersonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090012171BC6FECA0079C600 /* PersonCell.swift */; settings = {ASSET_TAGS = (); }; };
0900122C1BC6FECA0079C600 /* PersonProviderAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900121B1BC6FECA0079C600 /* PersonProviderAPI.swift */; settings = {ASSET_TAGS = (); }; };
0900122D1BC6FECA0079C600 /* DummyPilotProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900121C1BC6FECA0079C600 /* DummyPilotProvider.swift */; settings = {ASSET_TAGS = (); }; };
0900122E1BC6FECA0079C600 /* HardCodedStarshipProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900121D1BC6FECA0079C600 /* HardCodedStarshipProvider.swift */; settings = {ASSET_TAGS = (); }; };
0900122F1BC6FECA0079C600 /* PlistPersonProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900121E1BC6FECA0079C600 /* PlistPersonProvider.swift */; settings = {ASSET_TAGS = (); }; };
0900123B1BC6FF4D0079C600 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0900123A1BC6FF4D0079C600 /* Main.storyboard */; settings = {ASSET_TAGS = (); }; };
0900123D1BC7012A0079C600 /* StarshipProviderAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900123C1BC7012A0079C600 /* StarshipProviderAPI.swift */; settings = {ASSET_TAGS = (); }; };
090012401BC704C60079C600 /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900123F1BC704C60079C600 /* Person.swift */; settings = {ASSET_TAGS = (); }; };
090012421BC7059E0079C600 /* Starship.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090012411BC7059E0079C600 /* Starship.swift */; settings = {ASSET_TAGS = (); }; };
090012441BC708A00079C600 /* DummyStarshipProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090012431BC708A00079C600 /* DummyStarshipProvider.swift */; settings = {ASSET_TAGS = (); }; };
099022621BC123C000E76F43 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099022611BC123C000E76F43 /* AppDelegate.swift */; };
099022641BC123C000E76F43 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099022631BC123C000E76F43 /* ViewController.swift */; };
099022671BC123C000E76F43 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 099022651BC123C000E76F43 /* Main.storyboard */; };
099022691BC123C000E76F43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 099022681BC123C000E76F43 /* Assets.xcassets */; };
0990226C1BC123C000E76F43 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0990226A1BC123C000E76F43 /* LaunchScreen.storyboard */; };
607FACEC1AFB9204008FA782 /* SWAPIWebServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */; };
7BBD849465D99D9D1987AE6D /* Pods_DipTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304AD039660A2C58EB08D985 /* Pods_DipTests.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
84D8EBE5B2D583BEFB17C45A /* Pods_DipSampleApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FE9C70E965FF88C3F20AC76 /* Pods_DipSampleApp.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
09D795FF1BC71F5A003C68EB /* PersonListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D795FE1BC71F5A003C68EB /* PersonListViewController.swift */; settings = {ASSET_TAGS = (); }; };
09D796011BC722C0003C68EB /* StarshipListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796001BC722C0003C68EB /* StarshipListViewController.swift */; settings = {ASSET_TAGS = (); }; };
09D796031BC72691003C68EB /* StarshipCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796021BC72691003C68EB /* StarshipCell.swift */; settings = {ASSET_TAGS = (); }; };
09D796071BC73E8B003C68EB /* StoryboardConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796061BC73E8B003C68EB /* StoryboardConstants.swift */; settings = {ASSET_TAGS = (); }; };
09D7960D1BC7431C003C68EB /* FetchableTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7960C1BC7431C003C68EB /* FetchableTrait.swift */; settings = {ASSET_TAGS = (); }; };
09D796111BC97809003C68EB /* mainPilot.plist in Resources */ = {isa = PBXBuildFile; fileRef = 09D796101BC97809003C68EB /* mainPilot.plist */; settings = {ASSET_TAGS = (); }; };
09D796131BC9A5BC003C68EB /* SWAPIPersonProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */; settings = {ASSET_TAGS = (); }; };
09D796151BC9A5FC003C68EB /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796141BC9A5FC003C68EB /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
09D796171BC9B53D003C68EB /* URLSessionNetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796161BC9B53D003C68EB /* URLSessionNetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
09D796191BC9BA49003C68EB /* DependencyContainers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796181BC9BA49003C68EB /* DependencyContainers.swift */; settings = {ASSET_TAGS = (); }; };
09D7961B1BC9BE65003C68EB /* SWAPIStarshipProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */; settings = {ASSET_TAGS = (); }; };
09D7961D1BC9C62E003C68EB /* SWAPICommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */; settings = {ASSET_TAGS = (); }; };
09D796221BCA8305003C68EB /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796141BC9A5FC003C68EB /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
09D796231BCA833E003C68EB /* SWAPIPersonProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */; settings = {ASSET_TAGS = (); }; };
09D796241BCA8345003C68EB /* PersonProviderAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900121B1BC6FECA0079C600 /* PersonProviderAPI.swift */; settings = {ASSET_TAGS = (); }; };
09D796251BCA8345003C68EB /* StarshipProviderAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900123C1BC7012A0079C600 /* StarshipProviderAPI.swift */; settings = {ASSET_TAGS = (); }; };
09D796261BCA8348003C68EB /* SWAPIStarshipProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */; settings = {ASSET_TAGS = (); }; };
09D796271BCA8550003C68EB /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900123F1BC704C60079C600 /* Person.swift */; settings = {ASSET_TAGS = (); }; };
09D796281BCA8550003C68EB /* Starship.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090012411BC7059E0079C600 /* Starship.swift */; settings = {ASSET_TAGS = (); }; };
09D796291BCA86D4003C68EB /* SWAPICommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */; settings = {ASSET_TAGS = (); }; };
09D7962C1BCA8AD4003C68EB /* NetworkMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7962A1BCA8AB3003C68EB /* NetworkMock.swift */; settings = {ASSET_TAGS = (); }; };
09D7962F1BCA922E003C68EB /* SWAPIStarshipProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7962D1BCA91D3003C68EB /* SWAPIStarshipProviderTests.swift */; settings = {ASSET_TAGS = (); }; };
607FACEC1AFB9204008FA782 /* SWAPIPersonProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* SWAPIPersonProviderTests.swift */; };
7BBD849465D99D9D1987AE6D /* Pods_DipTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304AD039660A2C58EB08D985 /* Pods_DipTests.framework */; };
84D8EBE5B2D583BEFB17C45A /* Pods_DipSampleApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FE9C70E965FF88C3F20AC76 /* Pods_DipSampleApp.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
097D52E71BC13B0D006C893C /* WebServiceAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebServiceAPI.swift; sourceTree = "<group>"; };
097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonFactoryAPI.swift; sourceTree = "<group>"; };
097D52EC1BC16091006C893C /* Person.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = "<group>"; };
097D52EE1BC1611C006C893C /* SWAPIWebService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIWebService.swift; sourceTree = "<group>"; };
097D52F01BC161F7006C893C /* SerializerAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SerializerAPI.swift; sourceTree = "<group>"; };
097D52F41BC166F3006C893C /* JSONSerializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONSerializer.swift; sourceTree = "<group>"; };
097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIPersonFactory.swift; sourceTree = "<group>"; };
097D52F81BC17418006C893C /* PersonFormatterAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonFormatterAPI.swift; sourceTree = "<group>"; };
097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MassHeightFormatter.swift; sourceTree = "<group>"; };
097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EyesHairFormatter.swift; sourceTree = "<group>"; };
090012161BC6FECA0079C600 /* BaseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCell.swift; sourceTree = "<group>"; };
090012171BC6FECA0079C600 /* PersonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonCell.swift; sourceTree = "<group>"; };
0900121B1BC6FECA0079C600 /* PersonProviderAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonProviderAPI.swift; sourceTree = "<group>"; };
0900121C1BC6FECA0079C600 /* DummyPilotProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DummyPilotProvider.swift; sourceTree = "<group>"; };
0900121D1BC6FECA0079C600 /* HardCodedStarshipProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HardCodedStarshipProvider.swift; sourceTree = "<group>"; };
0900121E1BC6FECA0079C600 /* PlistPersonProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlistPersonProvider.swift; sourceTree = "<group>"; };
0900123A1BC6FF4D0079C600 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
0900123C1BC7012A0079C600 /* StarshipProviderAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarshipProviderAPI.swift; sourceTree = "<group>"; };
0900123F1BC704C60079C600 /* Person.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = "<group>"; };
090012411BC7059E0079C600 /* Starship.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Starship.swift; sourceTree = "<group>"; };
090012431BC708A00079C600 /* DummyStarshipProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DummyStarshipProvider.swift; sourceTree = "<group>"; };
097D52FE1BC18A09006C893C /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = "<group>"; };
097D53001BC31F4A006C893C /* Tags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tags.swift; sourceTree = "<group>"; };
097D53091BC3243D006C893C /* NetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkLayer.swift; sourceTree = "<group>"; };
097D530B1BC324DA006C893C /* NSURLSessionNetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLSessionNetworkLayer.swift; sourceTree = "<group>"; };
0990225F1BC123C000E76F43 /* DipSampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DipSampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
099022611BC123C000E76F43 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
099022631BC123C000E76F43 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
099022661BC123C000E76F43 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
099022681BC123C000E76F43 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0990226B1BC123C000E76F43 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
0990226D1BC123C000E76F43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
09D795FE1BC71F5A003C68EB /* PersonListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonListViewController.swift; sourceTree = "<group>"; };
09D796001BC722C0003C68EB /* StarshipListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarshipListViewController.swift; sourceTree = "<group>"; };
09D796021BC72691003C68EB /* StarshipCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarshipCell.swift; sourceTree = "<group>"; };
09D796061BC73E8B003C68EB /* StoryboardConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardConstants.swift; sourceTree = "<group>"; };
09D7960C1BC7431C003C68EB /* FetchableTrait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchableTrait.swift; sourceTree = "<group>"; };
09D796101BC97809003C68EB /* mainPilot.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = mainPilot.plist; sourceTree = "<group>"; };
09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIPersonProvider.swift; sourceTree = "<group>"; };
09D796141BC9A5FC003C68EB /* NetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkLayer.swift; sourceTree = "<group>"; };
09D796161BC9B53D003C68EB /* URLSessionNetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionNetworkLayer.swift; sourceTree = "<group>"; };
09D796181BC9BA49003C68EB /* DependencyContainers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DependencyContainers.swift; sourceTree = "<group>"; };
09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIStarshipProvider.swift; sourceTree = "<group>"; };
09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPICommon.swift; sourceTree = "<group>"; };
09D7962A1BCA8AB3003C68EB /* NetworkMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkMock.swift; sourceTree = "<group>"; };
09D7962D1BCA91D3003C68EB /* SWAPIStarshipProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIStarshipProviderTests.swift; sourceTree = "<group>"; };
2FE9C70E965FF88C3F20AC76 /* Pods_DipSampleApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipSampleApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
304AD039660A2C58EB08D985 /* Pods_DipTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
607FACE51AFB9204008FA782 /* DipTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DipTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SWAPIWebServiceTests.swift; sourceTree = "<group>"; };
607FACEB1AFB9204008FA782 /* SWAPIPersonProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SWAPIPersonProviderTests.swift; sourceTree = "<group>"; };
64B6CB26CB93DFD18565BB72 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
6AB71DAFECF410F2FB12A44C /* Pods-DipSampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DipSampleApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DipSampleApp/Pods-DipSampleApp.debug.xcconfig"; sourceTree = "<group>"; };
7E5EDFB4A9194B50CAED7E1A /* Pods-DipTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DipTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DipTests/Pods-DipTests.debug.xcconfig"; sourceTree = "<group>"; };
@@ -98,60 +114,92 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
097D52E61BC139A8006C893C /* Services */ = {
090012141BC6FECA0079C600 /* Cells */ = {
isa = PBXGroup;
children = (
097D52F21BC16258006C893C /* Protocols */,
097D52F31BC16271006C893C /* Implementations */,
090012161BC6FECA0079C600 /* BaseCell.swift */,
090012171BC6FECA0079C600 /* PersonCell.swift */,
09D796021BC72691003C68EB /* StarshipCell.swift */,
);
path = Services;
path = Cells;
sourceTree = "<group>";
};
097D52EB1BC16083006C893C /* Model */ = {
0900121A1BC6FECA0079C600 /* Providers */ = {
isa = PBXGroup;
children = (
097D52EC1BC16091006C893C /* Person.swift */,
09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */,
090012371BC6FEEA0079C600 /* APIs */,
090012381BC6FEFD0079C600 /* PersonProviders */,
090012391BC6FF080079C600 /* StarshipProviders */,
09D796161BC9B53D003C68EB /* URLSessionNetworkLayer.swift */,
);
path = Providers;
sourceTree = "<group>";
};
090012201BC6FECA0079C600 /* ViewControllers */ = {
isa = PBXGroup;
children = (
09D7960C1BC7431C003C68EB /* FetchableTrait.swift */,
09D795FE1BC71F5A003C68EB /* PersonListViewController.swift */,
09D796001BC722C0003C68EB /* StarshipListViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
};
090012371BC6FEEA0079C600 /* APIs */ = {
isa = PBXGroup;
children = (
0900121B1BC6FECA0079C600 /* PersonProviderAPI.swift */,
0900123C1BC7012A0079C600 /* StarshipProviderAPI.swift */,
09D796141BC9A5FC003C68EB /* NetworkLayer.swift */,
);
name = APIs;
sourceTree = "<group>";
};
090012381BC6FEFD0079C600 /* PersonProviders */ = {
isa = PBXGroup;
children = (
0900121C1BC6FECA0079C600 /* DummyPilotProvider.swift */,
0900121E1BC6FECA0079C600 /* PlistPersonProvider.swift */,
09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */,
);
name = PersonProviders;
sourceTree = "<group>";
};
090012391BC6FF080079C600 /* StarshipProviders */ = {
isa = PBXGroup;
children = (
090012431BC708A00079C600 /* DummyStarshipProvider.swift */,
0900121D1BC6FECA0079C600 /* HardCodedStarshipProvider.swift */,
09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */,
);
name = StarshipProviders;
sourceTree = "<group>";
};
0900123E1BC704A80079C600 /* Model */ = {
isa = PBXGroup;
children = (
0900123F1BC704C60079C600 /* Person.swift */,
090012411BC7059E0079C600 /* Starship.swift */,
);
path = Model;
sourceTree = "<group>";
};
097D52F21BC16258006C893C /* Protocols */ = {
isa = PBXGroup;
children = (
097D52E71BC13B0D006C893C /* WebServiceAPI.swift */,
097D52F01BC161F7006C893C /* SerializerAPI.swift */,
097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */,
097D52F81BC17418006C893C /* PersonFormatterAPI.swift */,
097D53091BC3243D006C893C /* NetworkLayer.swift */,
);
path = Protocols;
sourceTree = "<group>";
};
097D52F31BC16271006C893C /* Implementations */ = {
isa = PBXGroup;
children = (
097D52EE1BC1611C006C893C /* SWAPIWebService.swift */,
097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */,
097D52F41BC166F3006C893C /* JSONSerializer.swift */,
097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */,
097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */,
097D530B1BC324DA006C893C /* NSURLSessionNetworkLayer.swift */,
);
path = Implementations;
sourceTree = "<group>";
};
099022601BC123C000E76F43 /* DipSampleApp */ = {
isa = PBXGroup;
children = (
097D52EB1BC16083006C893C /* Model */,
097D52E61BC139A8006C893C /* Services */,
097D53001BC31F4A006C893C /* Tags.swift */,
0900123A1BC6FF4D0079C600 /* Main.storyboard */,
099022611BC123C000E76F43 /* AppDelegate.swift */,
099022631BC123C000E76F43 /* ViewController.swift */,
099022651BC123C000E76F43 /* Main.storyboard */,
09D796181BC9BA49003C68EB /* DependencyContainers.swift */,
0900123E1BC704A80079C600 /* Model */,
0900121A1BC6FECA0079C600 /* Providers */,
090012201BC6FECA0079C600 /* ViewControllers */,
090012141BC6FECA0079C600 /* Cells */,
099022681BC123C000E76F43 /* Assets.xcassets */,
09D796061BC73E8B003C68EB /* StoryboardConstants.swift */,
0990226A1BC123C000E76F43 /* LaunchScreen.storyboard */,
0990226D1BC123C000E76F43 /* Info.plist */,
09D796101BC97809003C68EB /* mainPilot.plist */,
);
path = DipSampleApp;
sourceTree = "<group>";
@@ -189,7 +237,9 @@
607FACE81AFB9204008FA782 /* Tests */ = {
isa = PBXGroup;
children = (
607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */,
09D7962A1BCA8AB3003C68EB /* NetworkMock.swift */,
607FACEB1AFB9204008FA782 /* SWAPIPersonProviderTests.swift */,
09D7962D1BCA91D3003C68EB /* SWAPIStarshipProviderTests.swift */,
607FACE91AFB9204008FA782 /* Supporting Files */,
);
path = Tests;
@@ -310,9 +360,10 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0900123B1BC6FF4D0079C600 /* Main.storyboard in Resources */,
0990226C1BC123C000E76F43 /* LaunchScreen.storyboard in Resources */,
09D796111BC97809003C68EB /* mainPilot.plist in Resources */,
099022691BC123C000E76F43 /* Assets.xcassets in Resources */,
099022671BC123C000E76F43 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -423,21 +474,28 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
097D530A1BC3243D006C893C /* NetworkLayer.swift in Sources */,
097D52ED1BC16091006C893C /* Person.swift in Sources */,
097D52F11BC161F7006C893C /* SerializerAPI.swift in Sources */,
097D52F91BC17418006C893C /* PersonFormatterAPI.swift in Sources */,
099022641BC123C000E76F43 /* ViewController.swift in Sources */,
097D530C1BC324DA006C893C /* NSURLSessionNetworkLayer.swift in Sources */,
097D52F51BC166F3006C893C /* JSONSerializer.swift in Sources */,
097D53011BC31F4A006C893C /* Tags.swift in Sources */,
09D796151BC9A5FC003C68EB /* NetworkLayer.swift in Sources */,
09D795FF1BC71F5A003C68EB /* PersonListViewController.swift in Sources */,
0900122A1BC6FECA0079C600 /* PersonCell.swift in Sources */,
09D796011BC722C0003C68EB /* StarshipListViewController.swift in Sources */,
0900122C1BC6FECA0079C600 /* PersonProviderAPI.swift in Sources */,
09D7961D1BC9C62E003C68EB /* SWAPICommon.swift in Sources */,
090012291BC6FECA0079C600 /* BaseCell.swift in Sources */,
0900122D1BC6FECA0079C600 /* DummyPilotProvider.swift in Sources */,
099022621BC123C000E76F43 /* AppDelegate.swift in Sources */,
097D52F71BC169C0006C893C /* SWAPIPersonFactory.swift in Sources */,
097D52EF1BC1611C006C893C /* SWAPIWebService.swift in Sources */,
097D52FD1BC174B6006C893C /* EyesHairFormatter.swift in Sources */,
097D52FB1BC1745B006C893C /* MassHeightFormatter.swift in Sources */,
097D52E81BC13B0D006C893C /* WebServiceAPI.swift in Sources */,
097D52EA1BC15FFF006C893C /* PersonFactoryAPI.swift in Sources */,
09D796131BC9A5BC003C68EB /* SWAPIPersonProvider.swift in Sources */,
090012421BC7059E0079C600 /* Starship.swift in Sources */,
0900123D1BC7012A0079C600 /* StarshipProviderAPI.swift in Sources */,
09D7961B1BC9BE65003C68EB /* SWAPIStarshipProvider.swift in Sources */,
0900122E1BC6FECA0079C600 /* HardCodedStarshipProvider.swift in Sources */,
09D796071BC73E8B003C68EB /* StoryboardConstants.swift in Sources */,
09D796031BC72691003C68EB /* StarshipCell.swift in Sources */,
090012401BC704C60079C600 /* Person.swift in Sources */,
090012441BC708A00079C600 /* DummyStarshipProvider.swift in Sources */,
09D7960D1BC7431C003C68EB /* FetchableTrait.swift in Sources */,
0900122F1BC6FECA0079C600 /* PlistPersonProvider.swift in Sources */,
09D796191BC9BA49003C68EB /* DependencyContainers.swift in Sources */,
09D796171BC9B53D003C68EB /* URLSessionNetworkLayer.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -445,33 +503,23 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
607FACEC1AFB9204008FA782 /* SWAPIWebServiceTests.swift in Sources */,
097D53051BC31FA6006C893C /* PersonFormatterAPI.swift in Sources */,
097D53071BC31FC5006C893C /* Tags.swift in Sources */,
097D53111BC32513006C893C /* NetworkLayer.swift in Sources */,
097D53021BC31FA6006C893C /* WebServiceAPI.swift in Sources */,
097D53041BC31FA6006C893C /* PersonFactoryAPI.swift in Sources */,
097D530E1BC3250E006C893C /* JSONSerializer.swift in Sources */,
097D53031BC31FA6006C893C /* SerializerAPI.swift in Sources */,
097D53081BC32053006C893C /* Person.swift in Sources */,
097D53101BC3250E006C893C /* EyesHairFormatter.swift in Sources */,
097D530F1BC3250E006C893C /* MassHeightFormatter.swift in Sources */,
097D530D1BC3250B006C893C /* SWAPIPersonFactory.swift in Sources */,
097D53061BC31FAE006C893C /* SWAPIWebService.swift in Sources */,
09D796291BCA86D4003C68EB /* SWAPICommon.swift in Sources */,
09D796221BCA8305003C68EB /* NetworkLayer.swift in Sources */,
09D796231BCA833E003C68EB /* SWAPIPersonProvider.swift in Sources */,
09D796251BCA8345003C68EB /* StarshipProviderAPI.swift in Sources */,
09D7962C1BCA8AD4003C68EB /* NetworkMock.swift in Sources */,
09D7962F1BCA922E003C68EB /* SWAPIStarshipProviderTests.swift in Sources */,
09D796241BCA8345003C68EB /* PersonProviderAPI.swift in Sources */,
09D796271BCA8550003C68EB /* Person.swift in Sources */,
607FACEC1AFB9204008FA782 /* SWAPIPersonProviderTests.swift in Sources */,
09D796261BCA8348003C68EB /* SWAPIStarshipProvider.swift in Sources */,
09D796281BCA8550003C68EB /* Starship.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
099022651BC123C000E76F43 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
099022661BC123C000E76F43 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
0990226A1BC123C000E76F43 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
+11 -14
View File
@@ -1,25 +1,12 @@
//
// AppDelegate.swift
// DipSampleApp
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
import Dip
let dip: DependencyContainer<PersonFormatterTag> = {
let dip = DependencyContainer<PersonFormatterTag>()
dip.register(instance: NSURLSessionNetworkLayer() as NetworkLayer)
dip.register(instance: SWAPIWebService() as WebServiceAPI)
dip.register(instance: SWAPIPersonFactory() as PersonFactoryAPI)
dip.register(instance: JSONSerializer() as SerializerAPI)
dip.register(.MassHeight, instance: MassHeightFormatter() as PersonFormatterAPI)
dip.register(.EyesHair, instance: EyesHairFormatter() as PersonFormatterAPI)
return dip
}()
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -29,6 +16,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if let tabBarVC = self.window?.rootViewController as? UITabBarController,
let vcs = tabBarVC.viewControllers as? [UINavigationController] {
if let personListVC = vcs[0].topViewController as? PersonListViewController {
personListVC.loadFirstPage()
}
if let starshipListVC = vcs[1].topViewController as? StarshipListViewController {
starshipListVC.loadFirstPage()
}
}
return true
}
}
@@ -21,8 +21,9 @@
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-120.png",
"scale" : "2x"
},
{
@@ -51,13 +52,15 @@
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-152.png",
"scale" : "2x"
}
],
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Churros.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "female.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "female@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "male.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "male@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "person@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "spaceship@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies>
<scenes>
<!--View Controller-->
@@ -15,8 +16,21 @@
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Churros" translatesAutoresizingMaskIntoConstraints="NO" id="Phj-6E-gSz">
<rect key="frame" x="0.0" y="20" width="600" height="580"/>
<animations/>
<color key="backgroundColor" red="0.40392156862745099" green="0.19215686274509805" blue="0.12549019607843137" alpha="1" colorSpace="calibratedRGB"/>
</imageView>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="Phj-6E-gSz" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="LGN-jG-FhR"/>
<constraint firstItem="Phj-6E-gSz" firstAttribute="top" secondItem="Llm-lL-Icb" secondAttribute="bottom" id="LqV-hP-9GR"/>
<constraint firstItem="xb3-aO-Qok" firstAttribute="top" secondItem="Phj-6E-gSz" secondAttribute="bottom" id="MYa-Zv-jEi"/>
<constraint firstAttribute="trailing" secondItem="Phj-6E-gSz" secondAttribute="trailing" id="zwN-fu-K6m"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -24,4 +38,7 @@
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="Churros" width="200" height="300"/>
</resources>
</document>
@@ -1,109 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="DipSampleApp" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="qXh-gx-TLm">
<rect key="frame" x="0.0" y="78" width="600" height="522"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="eJE-RI-YCj" detailTextLabel="bZ8-WN-uod" rowHeight="44" style="IBUITableViewCellStyleSubtitle" id="DrW-4I-t0H">
<rect key="frame" x="0.0" y="28" width="600" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DrW-4I-t0H" id="8qv-kr-bqA">
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="eJE-RI-YCj">
<rect key="frame" x="15" y="6" width="31.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="bZ8-WN-uod">
<rect key="frame" x="15" y="25.5" width="40.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
</tableViewCellContentView>
<animations/>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="BYZ-38-t0r" id="VJL-tj-MzD"/>
<outlet property="delegate" destination="BYZ-38-t0r" id="3VC-R7-cB4"/>
</connections>
</tableView>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="9iY-My-sX6">
<rect key="frame" x="373" y="29" width="207" height="29"/>
<animations/>
<segments>
<segment title="Mass &amp; Height"/>
<segment title="Hair &amp; Eyes"/>
</segments>
<connections>
<action selector="displayModeChanged:" destination="BYZ-38-t0r" eventType="valueChanged" id="CBv-S7-Hhz"/>
</connections>
</segmentedControl>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="ZrJ-F8-ur5">
<rect key="frame" x="110" y="33" width="20" height="20"/>
<animations/>
</activityIndicatorView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ncZ-ht-Ksy">
<rect key="frame" x="20" y="28" width="82" height="30"/>
<animations/>
<state key="normal" title="fetchPeople"/>
<connections>
<action selector="fetchPeople:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Mt6-Lr-Pil"/>
</connections>
</button>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="qXh-gx-TLm" secondAttribute="trailing" id="9Kr-bh-UDV"/>
<constraint firstItem="qXh-gx-TLm" firstAttribute="top" secondItem="ncZ-ht-Ksy" secondAttribute="bottom" constant="20" id="Hmb-DO-Rfc"/>
<constraint firstItem="9iY-My-sX6" firstAttribute="centerY" secondItem="ncZ-ht-Ksy" secondAttribute="centerY" id="TBb-VW-yeu"/>
<constraint firstItem="ncZ-ht-Ksy" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="20" symbolic="YES" id="U15-6S-bXH"/>
<constraint firstItem="ZrJ-F8-ur5" firstAttribute="leading" secondItem="ncZ-ht-Ksy" secondAttribute="trailing" constant="8" symbolic="YES" id="YZP-u9-4yj"/>
<constraint firstItem="ncZ-ht-Ksy" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="8" symbolic="YES" id="Zj6-fq-3iI"/>
<constraint firstItem="ZrJ-F8-ur5" firstAttribute="centerY" secondItem="ncZ-ht-Ksy" secondAttribute="centerY" id="g7i-I1-gh8"/>
<constraint firstItem="qXh-gx-TLm" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="hhU-qP-IoI"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="qXh-gx-TLm" secondAttribute="bottom" id="koO-On-68B"/>
<constraint firstAttribute="trailing" secondItem="9iY-My-sX6" secondAttribute="trailing" constant="20" symbolic="YES" id="wRA-OJ-Uzd"/>
</constraints>
</view>
<connections>
<outlet property="activityIndicator" destination="ZrJ-F8-ur5" id="3If-JS-Sph"/>
<outlet property="displayModeSelector" destination="9iY-My-sX6" id="UvA-Vu-rkk"/>
<outlet property="tableView" destination="qXh-gx-TLm" id="agu-go-Toa"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="390" y="450"/>
</scene>
</scenes>
</document>
+41
View File
@@ -0,0 +1,41 @@
//
// BaseCell.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
protocol BaseCell {
static var identifier: String { get }
static var nib: UINib? { get }
static func register(tableView: UITableView)
static func dequeueFromTableView(tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> Self
}
extension BaseCell where Self : UITableViewCell {
static var identifier: String {
return "\(Self.self)"
}
static var nib: UINib? { return nil }
static func register(tableView: UITableView) {
if let cellNib = self.nib {
tableView.registerNib(cellNib, forCellReuseIdentifier: identifier)
} else {
tableView.registerClass(Self.self as AnyClass, forCellReuseIdentifier: identifier)
}
}
static func dequeueFromTableView(tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> Self {
return tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! Self
}
}
protocol FillableCell: BaseCell {
typealias ObjectType
func fillWithObject(object: ObjectType)
}
@@ -0,0 +1,38 @@
//
// UserCell.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
final class PersonCell : UITableViewCell, FillableCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var genderImageView: UIImageView!
@IBOutlet weak var heightLabel: UILabel!
@IBOutlet weak var massLabel: UILabel!
@IBOutlet weak var hairLabel: UILabel!
@IBOutlet weak var eyesLabel: UILabel!
let heightFormatter: NSLengthFormatter = {
let f = NSLengthFormatter()
f.forPersonHeightUse = true
return f
}()
let massFormatter: NSMassFormatter = {
let f = NSMassFormatter()
f.forPersonMassUse = true
return f
}()
func fillWithObject(person: Person) {
nameLabel.text = person.name
genderImageView.image = person.gender.flatMap { UIImage(named: $0.rawValue) }
heightLabel.text = heightFormatter.stringFromValue(Double(person.height), unit: .Centimeter)
massLabel.text = massFormatter.stringFromValue(Double(person.mass), unit: .Kilogram)
hairLabel.text = person.hairColor
eyesLabel.text = person.eyeColor
}
}
@@ -0,0 +1,27 @@
//
// StarshipCell.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
final class StarshipCell : UITableViewCell, FillableCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var modelLabel: UILabel!
@IBOutlet weak var manufacturerLabel: UILabel!
@IBOutlet weak var crewLabel: UILabel!
@IBOutlet weak var passengersLabel: UILabel!
let numberFormatter = NSNumberFormatter()
func fillWithObject(starship: Starship) {
nameLabel.text = starship.name
modelLabel.text = starship.model
manufacturerLabel.text = starship.manufacturer
crewLabel.text = numberFormatter.stringFromNumber(starship.crew)
passengersLabel.text = numberFormatter.stringFromNumber(starship.passengers)
}
}
@@ -0,0 +1,59 @@
//
// DependencyContainers.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
// MARK: Configuration
/* Change this to toggle between real and fake data */
private let FAKE_PERSONS = false
private let FAKE_STARSHIPS = false
/* ---- */
// MARK: Dependency Container for WebServices & NetworkLayer
let wsDependencies = DependencyContainer() { dip in
// Register the NetworkLayer, same for everyone here (but we have the ability to register a different one for a specific WebService if we wanted to)
dip.register(instance: URLSessionNetworkLayer(baseURL: "http://swapi.co/api/")! as NetworkLayer)
}
// MARK: Dependency Container for Providers
let providerDependencies = DependencyContainer() { dip in
if FAKE_PERSONS {
// 1) Register the PersonProviderAPI singleton, one generic and one specific for a specific personID
dip.register(instance: DummyPilotProvider() as PersonProviderAPI)
dip.register(0, instance: PlistPersonProvider(plist: "mainPilot") as PersonProviderAPI)
} else {
// 1) Register the SWAPIPersonProvider (that hits the real swapi.co WebService)
dip.register(instance: SWAPIPersonProvider() as PersonProviderAPI)
}
if FAKE_STARSHIPS {
// 2) Register the StarshipProviderAPI factories, one generic and one specific for a specific starshipID
dip.register() { HardCodedStarshipProvider() as StarshipProviderAPI }
dip.register(0) { DummyStarshipProvider(pilotName: "Main Pilot") as StarshipProviderAPI }
} else {
// 2) Register the SWAPIStarshipProvider (that hits the real swapi.co WebService)
dip.register(instance: SWAPIStarshipProvider() as StarshipProviderAPI)
}
}
+364
View File
@@ -0,0 +1,364 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Nnt-Mi-Wf8">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<scenes>
<!--Tab Bar Controller-->
<scene sceneID="i0H-gd-FLz">
<objects>
<tabBarController id="Nnt-Mi-Wf8" sceneMemberID="viewController">
<tabBar key="tabBar" contentMode="scaleToFill" id="hlX-Lx-tB1">
<rect key="frame" x="0.0" y="0.0" width="320" height="49"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tabBar>
<connections>
<segue destination="mlz-mZ-4kR" kind="relationship" relationship="viewControllers" id="uTd-4n-koO"/>
<segue destination="OOn-QH-lHm" kind="relationship" relationship="viewControllers" id="xes-rT-62n"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="9gk-9q-7Lz" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-429" y="324"/>
</scene>
<!--Characters List-->
<scene sceneID="aeC-id-DL1">
<objects>
<tableViewController title="Characters List" id="I87-Zh-w4A" customClass="PersonListViewController" customModule="DipSampleApp" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="95" sectionHeaderHeight="28" sectionFooterHeight="28" id="EYu-RQ-JO9">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PersonCell" rowHeight="95" id="Sba-Wm-z4c" customClass="PersonCell" customModule="DipSampleApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="600" height="95"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Sba-Wm-z4c" id="UE9-zV-NsG">
<rect key="frame" x="0.0" y="0.0" width="567" height="94.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Name:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gVy-Vx-i2h">
<rect key="frame" x="8" y="8" width="49" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Height (cm):" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ymL-8F-Mpa">
<rect key="frame" x="8" y="35" width="94" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Mass (kg):" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9sd-2A-Ixx">
<rect key="frame" x="8" y="63" width="79" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Eyes:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YPu-dh-Fhf">
<rect key="frame" x="378" y="63" width="41" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="1CQ-rV-Y7c">
<rect key="frame" x="539" y="8" width="20" height="20"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="20" id="PK0-f1-YTg"/>
<constraint firstAttribute="height" constant="20" id="TOR-23-CAr"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-name-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GhU-yA-Nkj">
<rect key="frame" x="110" y="7" width="421" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-height-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VLd-vh-c8m">
<rect key="frame" x="110" y="34" width="260.5" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-mass-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zgG-Ij-dCY">
<rect key="frame" x="110" y="62" width="260" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-hair-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7TM-Aw-IPT">
<rect key="frame" x="427" y="34" width="120" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-eyes-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hv7-qr-iAY">
<rect key="frame" x="427" y="62" width="120" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Hair:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rDV-iQ-Ugd">
<rect key="frame" x="378" y="35" width="36.5" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstItem="Hv7-qr-iAY" firstAttribute="baseline" secondItem="YPu-dh-Fhf" secondAttribute="baseline" id="590-8v-aT3"/>
<constraint firstItem="zgG-Ij-dCY" firstAttribute="baseline" secondItem="9sd-2A-Ixx" secondAttribute="baseline" id="62H-PJ-mjV"/>
<constraint firstItem="gVy-Vx-i2h" firstAttribute="leading" secondItem="UE9-zV-NsG" secondAttribute="leading" constant="8" id="6PH-YE-0CH"/>
<constraint firstAttribute="trailing" secondItem="7TM-Aw-IPT" secondAttribute="trailing" constant="20" symbolic="YES" id="9Wo-lL-3sH"/>
<constraint firstItem="VLd-vh-c8m" firstAttribute="leading" secondItem="GhU-yA-Nkj" secondAttribute="leading" id="BdD-7S-2XA"/>
<constraint firstItem="7TM-Aw-IPT" firstAttribute="baseline" secondItem="rDV-iQ-Ugd" secondAttribute="baseline" id="DI8-mB-O2Q"/>
<constraint firstItem="rDV-iQ-Ugd" firstAttribute="leading" secondItem="UE9-zV-NsG" secondAttribute="trailing" multiplier="2:3" id="FF6-Qm-k9s"/>
<constraint firstItem="Hv7-qr-iAY" firstAttribute="leading" secondItem="YPu-dh-Fhf" secondAttribute="trailing" constant="8" symbolic="YES" id="Lfl-NE-XQw"/>
<constraint firstItem="GhU-yA-Nkj" firstAttribute="baseline" secondItem="gVy-Vx-i2h" secondAttribute="baseline" id="Ofa-oe-uss"/>
<constraint firstItem="ymL-8F-Mpa" firstAttribute="leading" secondItem="gVy-Vx-i2h" secondAttribute="leading" id="PLY-0s-RbV"/>
<constraint firstItem="9sd-2A-Ixx" firstAttribute="baseline" secondItem="YPu-dh-Fhf" secondAttribute="baseline" id="T7J-SS-1Xi"/>
<constraint firstItem="VLd-vh-c8m" firstAttribute="baseline" secondItem="ymL-8F-Mpa" secondAttribute="baseline" id="Tia-Ni-Vh5"/>
<constraint firstItem="9sd-2A-Ixx" firstAttribute="top" secondItem="ymL-8F-Mpa" secondAttribute="bottom" constant="8" symbolic="YES" id="X8o-RN-a1C"/>
<constraint firstItem="gVy-Vx-i2h" firstAttribute="top" secondItem="UE9-zV-NsG" secondAttribute="top" constant="8" id="bJk-O2-lbx"/>
<constraint firstItem="1CQ-rV-Y7c" firstAttribute="top" secondItem="UE9-zV-NsG" secondAttribute="top" constant="8" id="cYB-OW-rRW"/>
<constraint firstItem="7TM-Aw-IPT" firstAttribute="leading" secondItem="Hv7-qr-iAY" secondAttribute="leading" id="cmD-JT-ghd"/>
<constraint firstItem="YPu-dh-Fhf" firstAttribute="leading" secondItem="rDV-iQ-Ugd" secondAttribute="leading" id="eKk-NU-W02"/>
<constraint firstItem="1CQ-rV-Y7c" firstAttribute="leading" secondItem="GhU-yA-Nkj" secondAttribute="trailing" constant="8" symbolic="YES" id="hTk-Jw-dhO"/>
<constraint firstItem="zgG-Ij-dCY" firstAttribute="leading" secondItem="VLd-vh-c8m" secondAttribute="leading" id="hol-S5-LT7"/>
<constraint firstItem="9sd-2A-Ixx" firstAttribute="leading" secondItem="gVy-Vx-i2h" secondAttribute="leading" id="jVj-RE-Kv4"/>
<constraint firstItem="ymL-8F-Mpa" firstAttribute="top" secondItem="gVy-Vx-i2h" secondAttribute="bottom" constant="8" symbolic="YES" id="jYg-8A-h30"/>
<constraint firstItem="YPu-dh-Fhf" firstAttribute="leading" secondItem="zgG-Ij-dCY" secondAttribute="trailing" constant="8" symbolic="YES" id="jgN-Jc-mRd"/>
<constraint firstAttribute="trailing" secondItem="1CQ-rV-Y7c" secondAttribute="trailing" constant="8" id="qWa-gr-wSb"/>
<constraint firstItem="VLd-vh-c8m" firstAttribute="leading" secondItem="ymL-8F-Mpa" secondAttribute="trailing" constant="8" symbolic="YES" id="qd0-di-L20"/>
<constraint firstAttribute="trailing" secondItem="Hv7-qr-iAY" secondAttribute="trailing" constant="20" symbolic="YES" id="rf5-zR-d5A"/>
<constraint firstItem="ymL-8F-Mpa" firstAttribute="baseline" secondItem="rDV-iQ-Ugd" secondAttribute="baseline" id="rfc-9C-LV2"/>
<constraint firstItem="rDV-iQ-Ugd" firstAttribute="leading" secondItem="VLd-vh-c8m" secondAttribute="trailing" constant="8" symbolic="YES" id="xL3-7N-f8f"/>
</constraints>
</tableViewCellContentView>
<animations/>
<connections>
<outlet property="eyesLabel" destination="Hv7-qr-iAY" id="bhd-4V-chX"/>
<outlet property="genderImageView" destination="1CQ-rV-Y7c" id="8rr-1s-qr4"/>
<outlet property="hairLabel" destination="7TM-Aw-IPT" id="dAf-MI-uUO"/>
<outlet property="heightLabel" destination="VLd-vh-c8m" id="kSS-Bb-x2Q"/>
<outlet property="massLabel" destination="zgG-Ij-dCY" id="uvZ-9b-t6A"/>
<outlet property="nameLabel" destination="GhU-yA-Nkj" id="NhU-k6-3Yf"/>
<segue destination="nuL-fZ-hCQ" kind="show" identifier="StarshipsSegue" id="zjp-Bb-fTw"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="I87-Zh-w4A" id="PQZ-xC-mLk"/>
<outlet property="delegate" destination="I87-Zh-w4A" id="BLg-fj-DdF"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Characters" id="Mue-vf-EYa"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="OIv-XM-enw" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1232" y="-39"/>
</scene>
<!--Starship List-->
<scene sceneID="Hu2-NE-Uko">
<objects>
<tableViewController title="Starship List" id="nuL-fZ-hCQ" customClass="StarshipListViewController" customModule="DipSampleApp" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="102" sectionHeaderHeight="28" sectionFooterHeight="28" id="uPj-BZ-JVx">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="StarshipCell" rowHeight="102" id="rfe-RG-ql1" customClass="StarshipCell" customModule="DipSampleApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="600" height="102"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="rfe-RG-ql1" id="RHz-uO-ANq">
<rect key="frame" x="0.0" y="0.0" width="567" height="101.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Name:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pR4-Aq-S9H">
<rect key="frame" x="8" y="8" width="49" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Model:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="V8k-Fh-teX">
<rect key="frame" x="8" y="33" width="52" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="Manufacturer:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iWU-h6-HNF">
<rect key="frame" x="8" y="61" width="108" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Crew:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JoH-bT-HcN">
<rect key="frame" x="460" y="33" width="44.5" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Pass:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="arT-4h-pLt">
<rect key="frame" x="463" y="61" width="41" height="19.5"/>
<animations/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-name-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lwe-Ix-EQE">
<rect key="frame" x="124" y="7" width="423" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="500" text="-model-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kIz-wz-fGn">
<rect key="frame" x="124" y="32" width="328" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="500" text="-manufacturer-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fVY-W3-78a">
<rect key="frame" x="124" y="60" width="331" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-crew-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WGV-Ar-PMC">
<rect key="frame" x="512" y="32" width="35" height="20.5"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="35" id="tsk-nr-zwr"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-pass-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YnA-qH-8AA">
<rect key="frame" x="512" y="60" width="35" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstAttribute="trailing" secondItem="YnA-qH-8AA" secondAttribute="trailing" constant="20" symbolic="YES" id="0iR-Ax-Tba"/>
<constraint firstItem="pR4-Aq-S9H" firstAttribute="leading" secondItem="iWU-h6-HNF" secondAttribute="leading" id="1dW-gb-Qyn"/>
<constraint firstItem="arT-4h-pLt" firstAttribute="leading" secondItem="fVY-W3-78a" secondAttribute="trailing" constant="8" symbolic="YES" id="47f-0O-zim"/>
<constraint firstItem="arT-4h-pLt" firstAttribute="baseline" secondItem="YnA-qH-8AA" secondAttribute="baseline" id="EFd-qL-pg5"/>
<constraint firstItem="iWU-h6-HNF" firstAttribute="baseline" secondItem="fVY-W3-78a" secondAttribute="baseline" id="HvJ-2u-LrS"/>
<constraint firstItem="YnA-qH-8AA" firstAttribute="leading" secondItem="arT-4h-pLt" secondAttribute="trailing" constant="8" symbolic="YES" id="KYF-WR-rp6"/>
<constraint firstItem="pR4-Aq-S9H" firstAttribute="top" secondItem="RHz-uO-ANq" secondAttribute="top" constant="8" id="TiY-OB-yeR"/>
<constraint firstItem="fVY-W3-78a" firstAttribute="leading" secondItem="iWU-h6-HNF" secondAttribute="trailing" constant="8" symbolic="YES" id="U0F-Gs-gHJ"/>
<constraint firstItem="JoH-bT-HcN" firstAttribute="leading" secondItem="kIz-wz-fGn" secondAttribute="trailing" constant="8" symbolic="YES" id="UZ7-nc-vsM"/>
<constraint firstAttribute="trailing" secondItem="WGV-Ar-PMC" secondAttribute="trailing" constant="20" symbolic="YES" id="ZSI-dG-LOG"/>
<constraint firstItem="pR4-Aq-S9H" firstAttribute="leading" secondItem="RHz-uO-ANq" secondAttribute="leading" constant="8" id="a1p-vg-3vU"/>
<constraint firstItem="V8k-Fh-teX" firstAttribute="baseline" secondItem="JoH-bT-HcN" secondAttribute="baseline" id="b7R-xY-Q2K"/>
<constraint firstItem="iWU-h6-HNF" firstAttribute="top" secondItem="V8k-Fh-teX" secondAttribute="bottom" constant="8" symbolic="YES" id="c1W-jc-Ny3"/>
<constraint firstItem="V8k-Fh-teX" firstAttribute="baseline" secondItem="kIz-wz-fGn" secondAttribute="baseline" id="c6b-gs-obR"/>
<constraint firstItem="WGV-Ar-PMC" firstAttribute="leading" secondItem="JoH-bT-HcN" secondAttribute="trailing" constant="8" symbolic="YES" id="ds0-kr-CtN"/>
<constraint firstItem="Lwe-Ix-EQE" firstAttribute="leading" secondItem="kIz-wz-fGn" secondAttribute="leading" id="g1a-qF-dcA"/>
<constraint firstAttribute="trailing" secondItem="Lwe-Ix-EQE" secondAttribute="trailing" constant="20" symbolic="YES" id="lp2-Wc-HdY"/>
<constraint firstItem="V8k-Fh-teX" firstAttribute="top" secondItem="pR4-Aq-S9H" secondAttribute="bottom" constant="6" id="mdN-0q-C8z"/>
<constraint firstItem="kIz-wz-fGn" firstAttribute="leading" secondItem="fVY-W3-78a" secondAttribute="leading" id="qSW-by-cCG"/>
<constraint firstItem="pR4-Aq-S9H" firstAttribute="baseline" secondItem="Lwe-Ix-EQE" secondAttribute="baseline" id="qwh-VM-sLX"/>
<constraint firstItem="JoH-bT-HcN" firstAttribute="baseline" secondItem="WGV-Ar-PMC" secondAttribute="baseline" id="s6z-70-Htc"/>
<constraint firstItem="iWU-h6-HNF" firstAttribute="baseline" secondItem="arT-4h-pLt" secondAttribute="baseline" id="u8F-qk-hFQ"/>
<constraint firstItem="pR4-Aq-S9H" firstAttribute="leading" secondItem="V8k-Fh-teX" secondAttribute="leading" id="waE-gT-CGh"/>
<constraint firstItem="WGV-Ar-PMC" firstAttribute="leading" secondItem="YnA-qH-8AA" secondAttribute="leading" id="ycM-ic-t05"/>
</constraints>
</tableViewCellContentView>
<animations/>
<connections>
<outlet property="crewLabel" destination="WGV-Ar-PMC" id="f6d-9q-59z"/>
<outlet property="manufacturerLabel" destination="fVY-W3-78a" id="ABE-NG-bZY"/>
<outlet property="modelLabel" destination="kIz-wz-fGn" id="DCN-Xs-efw"/>
<outlet property="nameLabel" destination="Lwe-Ix-EQE" id="3Oq-qm-T4Q"/>
<outlet property="passengersLabel" destination="YnA-qH-8AA" id="Mns-H6-3Cd"/>
<segue destination="I87-Zh-w4A" kind="show" identifier="PilotsSegue" id="Yvy-aQ-caa"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="nuL-fZ-hCQ" id="Fzz-8K-PVH"/>
<outlet property="delegate" destination="nuL-fZ-hCQ" id="crW-zS-Nsx"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Starships" id="krH-S8-MNL"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2q4-tT-9DC" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1232" y="684"/>
</scene>
<!--Starships-->
<scene sceneID="5hS-an-4XB">
<objects>
<navigationController title="Starships" id="OOn-QH-lHm" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Starships" image="spaceship" id="75v-7I-9RA"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="VfI-ho-mqu">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
</navigationBar>
<connections>
<segue destination="nuL-fZ-hCQ" kind="relationship" relationship="rootViewController" id="l50-ri-Dfy"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Z5g-Su-noc" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="345" y="684"/>
</scene>
<!--Characters-->
<scene sceneID="oGL-ha-Mxk">
<objects>
<navigationController title="Characters" id="mlz-mZ-4kR" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Characters" image="person" id="9Al-Aa-Mx2"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="YPS-Al-CkA">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
</navigationBar>
<connections>
<segue destination="I87-Zh-w4A" kind="relationship" relationship="rootViewController" id="07W-Xm-zjJ"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="A0c-c7-DAG" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="345" y="-39"/>
</scene>
</scenes>
<resources>
<image name="person" width="22" height="22"/>
<image name="spaceship" width="22" height="22"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="zjp-Bb-fTw"/>
<segue reference="Yvy-aQ-caa"/>
</inferredMetricsTieBreakers>
</document>
+9 -2
View File
@@ -2,16 +2,23 @@
// Person.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Created by Olivier Halligon on 08/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
enum Gender: String {
case Male = "male"
case Female = "female"
}
struct Person {
var name: String
var height: Int
var mass: Int
var eyesColor: String
var hairColor: String
var eyeColor: String
var gender: Gender?
var starshipIDs: [Int]
}
+18
View File
@@ -0,0 +1,18 @@
//
// Starship.swift
// Dip
//
// Created by Olivier Halligon on 08/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
struct Starship {
var name: String
var model: String
var manufacturer: String
var crew: Int
var passengers: Int
var pilotIDs: [Int]
}
@@ -0,0 +1,34 @@
//
// DummyPilotProvider.swift
// Dip
//
// Created by Olivier Halligon on 12/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
struct DummyPilotProvider : PersonProviderAPI {
func fetchIDs(completion: [Int] -> Void) {
completion(Array(0..<5))
}
func fetch(id: Int, completion: Person? -> Void) {
completion(dummyPerson(id))
}
private func dummyPerson(idx: Int) -> Person {
let colors = ["blue", "brown", "yellow", "orange", "red", "dark"]
let genders: [Gender?] = [Gender.Male, Gender.Female, nil]
return Person(
name: "John Dummy Doe #\(idx)",
height: 150 + (idx*27%40),
mass: 50 + (idx*7%30),
hairColor: colors[idx*3%colors.count],
eyeColor: colors[idx*2%colors.count],
gender: genders[idx%3],
starshipIDs: [idx % 3, 2*idx % 4]
)
}
}
@@ -0,0 +1,33 @@
//
// DummyStarshipProvider.swift
// Dip
//
// Created by Olivier Halligon on 08/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
struct DummyStarshipProvider : StarshipProviderAPI {
var pilotName: String
func fetchIDs(completion: [Int] -> Void) {
let nbShips = pilotName.characters.count
completion(Array(0..<nbShips))
}
func fetch(id: Int, completion: Starship? -> Void) {
completion(dummyStarship(id))
}
private func dummyStarship(idx: Int) -> Starship {
return Starship(
name: "\(pilotName)'s awesome starship #\(idx)",
model: "\(pilotName)Ship",
manufacturer: "Dummy Industries",
crew: 1 + (idx%3),
passengers: 10 + (idx*7 % 40),
pilotIDs: [idx]
)
}
}
@@ -0,0 +1,30 @@
//
// HardCodedStarshipProvider.swift
// Dip
//
// Created by Olivier Halligon on 11/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
class HardCodedStarshipProvider : StarshipProviderAPI {
let starships = [
Starship(name: "First Ship", model: "AwesomeShip", manufacturer: "HardCoded Inc.", crew: 3, passengers: 20, pilotIDs: [1,2]),
Starship(name: "Second Ship", model: "AwesomeShip Express", manufacturer: "HardCoded Inc.", crew: 4, passengers: 10, pilotIDs: [1]),
Starship(name: "Third Ship", model: "AwesomeShip Cargo", manufacturer: "HardCoded Inc.", crew: 12, passengers: 150, pilotIDs: [2]),
] + Array(4..<75).map { Starship(name: "Ship #\($0)", model: "AwesomeShip Fighter", manufacturer: "HardCoded Inc.", crew: 1, passengers: 2, pilotIDs: [1]) }
func fetchIDs(completion: [Int] -> Void) {
completion(Array(0..<starships.count))
}
func fetch(id: Int, completion: Starship? -> Void) {
guard id < starships.count else {
completion(nil)
return
}
completion(starships[id])
}
}
@@ -0,0 +1,36 @@
//
// NetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
enum NetworkResponse {
case Success(NSData, NSHTTPURLResponse)
case Error(NSError)
func unwrap() throws -> (NSData, NSHTTPURLResponse) {
switch self {
case Success(let data, let response):
return (data, response)
case Error(let error):
throw error
}
}
func json<T>() throws -> T {
let (data, _) = try self.unwrap()
let obj = try NSJSONSerialization.JSONObjectWithData(data, options: [])
guard let json = obj as? T else {
throw SWAPIError.InvalidJSON
}
return json
}
}
protocol NetworkLayer {
func request(path: String, completion: NetworkResponse -> Void)
}
@@ -0,0 +1,14 @@
//
// PersonProviderAPI.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol PersonProviderAPI {
func fetchIDs(completion: [Int] -> Void)
func fetch(id: Int, completion: Person? -> Void)
}
@@ -0,0 +1,61 @@
//
// PlistPersonProvider.swift
// Dip
//
// Created by Olivier Halligon on 12/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
class PlistPersonProvider : PersonProviderAPI {
let people: [Person]
init(plist basename: String) {
guard
let path = NSBundle.mainBundle().pathForResource(basename, ofType: "plist"),
let list = NSArray(contentsOfFile: path),
peopleDict = list as? [[String:AnyObject]]
else {
fatalError("PLIST for \(basename) not found")
}
self.people = peopleDict.map(PlistPersonProvider.personFromDict)
}
func fetchIDs(completion: [Int] -> Void) {
completion(Array(0..<people.count))
}
func fetch(id: Int, completion: Person? -> Void) {
guard id < people.count else {
completion(nil)
return
}
completion(people[id])
}
private static func personFromDict(dict: [String:AnyObject]) -> Person {
guard
let name = dict["name"] as? String,
height = dict["height"] as? Int,
mass = dict["mass"] as? Int,
hairColor = dict["hairColor"] as? String,
eyeColor = dict["eyeColor"] as? String,
genderStr = dict["gender"] as? String,
starshipsIDs = dict["starships"] as? [Int]
else {
fatalError("Invalid Plist")
}
return Person(
name: name,
height: height,
mass: mass,
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: genderStr),
starshipIDs: starshipsIDs
)
}
}
@@ -0,0 +1,26 @@
//
// SWAPICommon.swift
// Dip
//
// Created by Olivier Halligon on 11/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
enum SWAPIError: ErrorType {
case InvalidJSON
}
enum WebService: String {
case PersonWS
case StarshipWS
var tag: DependencyContainer.Tag { return DependencyContainer.Tag.String(self.rawValue) }
}
func idFromURLString(urlString: String) -> Int? {
let url = NSURL(string: urlString)
let idString = url.flatMap { $0.lastPathComponent }
return idString.flatMap { Int($0) }
}
@@ -0,0 +1,64 @@
//
// SWAPIPersonProvider.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
struct SWAPIPersonProvider : PersonProviderAPI {
let ws = wsDependencies.resolve(WebService.PersonWS.tag) as NetworkLayer
func fetchIDs(completion: [Int] -> Void) {
ws.request("people") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
completion(ids)
}
catch {
completion([])
}
}
}
func fetch(id: Int, completion: Person? -> Void) {
ws.request("people/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let heightStr = json["height"] as? String, height = Int(heightStr),
let massStr = json["mass"] as? String, mass = Int(massStr),
let hairColor = json["hair_color"] as? String,
let eyeColor = json["eye_color"] as? String,
let gender = json["gender"] as? String,
let starshipURLStrings = json["starships"] as? [String]
else {
throw SWAPIError.InvalidJSON
}
let person = Person(
name: name,
height: height,
mass: mass,
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: gender),
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
)
completion(person)
}
catch {
completion(nil)
}
}
}
}
@@ -0,0 +1,62 @@
//
// SWAPIStarshipProvider.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
struct SWAPIStarshipProvider : StarshipProviderAPI {
let ws = wsDependencies.resolve(WebService.StarshipWS.tag) as NetworkLayer
func fetchIDs(completion: [Int] -> Void) {
ws.request("starships") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
completion(ids)
}
catch {
completion([])
}
}
}
func fetch(id: Int, completion: Starship? -> Void) {
ws.request("starships/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let model = json["model"] as? String,
let manufacturer = json["manufacturer"] as? String,
let crewStr = json["crew"] as? String, crew = Int(crewStr),
let passengersStr = json["passengers"] as? String, passengers = Int(passengersStr),
let pilotIDStrings = json["pilots"] as? [String]
else {
throw SWAPIError.InvalidJSON
}
let ship = Starship(
name: name,
model: model,
manufacturer: manufacturer,
crew: crew,
passengers: passengers,
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
)
completion(ship)
}
catch {
completion(nil)
}
}
}
}
@@ -0,0 +1,14 @@
//
// StarshipProviderAPI.swift
// Dip
//
// Created by Olivier Halligon on 08/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol StarshipProviderAPI {
func fetchIDs(completion: [Int] -> Void)
func fetch(id: Int, completion: Starship? -> Void)
}
@@ -0,0 +1,44 @@
//
// URLSessionNetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
struct URLSessionNetworkLayer : NetworkLayer {
let baseURL: NSURL
let session: NSURLSession
let responseQueue: dispatch_queue_t
init?(baseURL: String, session: NSURLSession = .sharedSession(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
guard let url = NSURL(string: baseURL) else { return nil }
self.init(baseURL: url, session: session)
}
init(baseURL: NSURL, session: NSURLSession = .sharedSession(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
self.baseURL = baseURL
self.session = session
self.responseQueue = responseQueue
}
func request(path: String, completion: NetworkResponse -> Void) {
let url = self.baseURL.URLByAppendingPathComponent(path)
let task = session.dataTaskWithURL(url) { data, response, error in
if let data = data, let response = response as? NSHTTPURLResponse {
dispatch_async(self.responseQueue) {
completion(NetworkResponse.Success(data, response))
}
}
else {
let err = error ?? NSError(domain: NSURLErrorDomain, code: NSURLError.Unknown.rawValue, userInfo: nil)
dispatch_async(self.responseQueue) {
completion(NetworkResponse.Error(err))
}
}
}
task.resume()
}
}
@@ -1,18 +0,0 @@
//
// EyesHairFormatter.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
class EyesHairFormatter : PersonFormatterAPI {
func textForPerson(person: Person) -> String {
return person.name
}
func subtextForPerson(person: Person) -> String {
return "\(person.eyesColor) eyes, \(person.hairColor) hair"
}
}
@@ -1,24 +0,0 @@
//
// JSONSerializer.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
class JSONSerializer : SerializerAPI {
enum Error : ErrorType {
case UnexpectedFormat
}
func dictionaryFromData(data: NSData) throws -> [String:AnyObject] {
let result = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let json = result as? [String:AnyObject] {
return json
} else {
throw Error.UnexpectedFormat
}
}
}
@@ -1,18 +0,0 @@
//
// MassHeightFormatter.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
class MassHeightFormatter : PersonFormatterAPI {
func textForPerson(person: Person) -> String {
return person.name
}
func subtextForPerson(person: Person) -> String {
return "\(person.mass)kg, \(person.height)cm"
}
}
@@ -1,22 +0,0 @@
//
// NSURLSessionNetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 05/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
class NSURLSessionNetworkLayer : NetworkLayer {
let session = NSURLSession.sharedSession()
func fetchURL(url: NSURL, completion: NSData? -> Void) {
let task = session.dataTaskWithURL(url) { (data: NSData?, resp: NSURLResponse?, error: NSError?) -> Void in
dispatch_async(dispatch_get_main_queue()) {
completion(data)
}
}
task.resume()
}
}
@@ -1,46 +0,0 @@
//
// SWAPIPersonFactory.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
class SWAPIPersonFactory : PersonFactoryAPI {
typealias JSONDict = [String:AnyObject]
enum Error : ErrorType {
case MissingResultsEntry
case InvalidPersonSchema
}
let serializer = dip.resolve() as SerializerAPI
func peopleFromData(personData: NSData) throws -> [Person] {
let json = try serializer.dictionaryFromData(personData)
if let results = json["results"] as? [JSONDict] {
return try results.map { try personFromJSON($0) }
} else {
throw Error.MissingResultsEntry
}
}
func personFromData(personData: NSData) throws -> Person {
let json = try serializer.dictionaryFromData(personData)
return try personFromJSON(json)
}
private func personFromJSON(json: JSONDict) throws -> Person {
guard let name = json["name"] as? String,
let heightStr = json["height"] as? String, height = Int(heightStr),
let massStr = json["mass"] as? String, mass = Int(massStr),
let eyesColor = json["eye_color"] as? String,
let hairColor = json["hair_color"] as? String
else {
throw Error.InvalidPersonSchema
}
return Person(name: name, height: height, mass: mass, eyesColor: eyesColor, hairColor: hairColor)
}
}
@@ -1,31 +0,0 @@
//
// SWAPIWebService.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
/// WebService for The StarWars API see http://swapi.co/documentation
class SWAPIWebService : WebServiceAPI {
let networkLayer = dip.resolve() as NetworkLayer
let personFactory = dip.resolve() as PersonFactoryAPI
func fetch(completion: [Person]? -> Void) {
let url = NSURL(string: "http://swapi.co/api/people/")!
networkLayer.fetchURLAndMap(url, completion: completion) { data in
return try self.personFactory.peopleFromData(data)
}
}
func fetch(id: Int, completion: Person? -> Void) {
let url = NSURL(string: "http://swapi.co/api/people/\(id)")!
networkLayer.fetchURLAndMap(url, completion: completion) { data in
return try self.personFactory.personFromData(data)
}
}
}
@@ -1,32 +0,0 @@
//
// NetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 05/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol NetworkLayer {
func fetchURL(url: NSURL, completion: NSData? -> Void)
func fetchURLAndMap<T>(url: NSURL, completion: T? -> Void, transform: NSData throws -> T)
}
extension NetworkLayer {
func fetchURLAndMap<T>(url: NSURL, completion: T? -> Void, transform: NSData throws -> T) {
fetchURL(url) { (data: NSData?) -> Void in
guard let data = data else {
completion(nil)
return
}
let result: T?
do {
result = try transform(data)
} catch {
result = nil
}
completion(result)
}
}
}
@@ -1,14 +0,0 @@
//
// PersonFactoryAPI.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol PersonFactoryAPI {
func peopleFromData(personData: NSData) throws -> [Person]
func personFromData(personData: NSData) throws -> Person
}
@@ -1,14 +0,0 @@
//
// PersonFormatterAPI.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol PersonFormatterAPI {
func textForPerson(person: Person) -> String
func subtextForPerson(person: Person) -> String
}
@@ -1,13 +0,0 @@
//
// SerializerAPI.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol SerializerAPI {
func dictionaryFromData(data: NSData) throws -> [String:AnyObject]
}
@@ -1,14 +0,0 @@
//
// WebServiceAPI.swift
// Dip
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
protocol WebServiceAPI {
func fetch(completion: [Person]? -> Void)
func fetch(id: Int, completion: Person? -> Void)
}
@@ -0,0 +1,48 @@
// Generated using SwiftGen, by O.Halligon https://github.com/AliSoftware/SwiftGen
import Foundation
import UIKit
protocol StoryboardScene : RawRepresentable {
static var storyboardName : String { get }
static func storyboard() -> UIStoryboard
static func initialViewController() -> UIViewController
func viewController() -> UIViewController
static func viewController(identifier: Self) -> UIViewController
}
extension StoryboardScene where Self.RawValue == String {
static func storyboard() -> UIStoryboard {
return UIStoryboard(name: self.storyboardName, bundle: nil)
}
static func initialViewController() -> UIViewController {
return storyboard().instantiateInitialViewController()!
}
func viewController() -> UIViewController {
return Self.storyboard().instantiateViewControllerWithIdentifier(self.rawValue)
}
static func viewController(identifier: Self) -> UIViewController {
return identifier.viewController()
}
}
extension UIStoryboard {
struct Scene {
enum Main {
static let storyboardName = "Main"
}
enum LaunchScreen {
static let storyboardName = "LaunchScreen"
}
}
struct Segue {
enum Main : String {
case StarshipsSegue = "StarshipsSegue"
case PilotsSegue = "PilotsSegue"
}
}
}
-14
View File
@@ -1,14 +0,0 @@
//
// Tags.swift
// Dip
//
// Created by Olivier Halligon on 05/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
enum PersonFormatterTag {
case MassHeight
case EyesHair
}
-64
View File
@@ -1,64 +0,0 @@
//
// ViewController.swift
// DipSampleApp
//
// Created by Olivier Halligon on 04/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
import Dip
let kCellIdentifier = "Cell"
class ViewController: UIViewController {
let ws = dip.resolve() as WebServiceAPI
var personList = [Person]()
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var displayModeSelector: UISegmentedControl!
@IBAction func fetchPeople(sender: UIButton) {
sender.enabled = false
self.activityIndicator.startAnimating()
ws.fetch { persons in
self.activityIndicator.stopAnimating()
sender.enabled = true
self.personList = persons ?? []
self.tableView.reloadData()
}
}
@IBAction func displayModeChanged(sender: UISegmentedControl) {
self.tableView.reloadData()
}
}
extension ViewController : UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.personList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier, forIndexPath: indexPath)
let person = personList[indexPath.row]
let formatter = dip.resolve(formatterTag) as PersonFormatterAPI
cell.textLabel?.text = formatter.textForPerson(person)
cell.detailTextLabel?.text = formatter.subtextForPerson(person)
return cell
}
var formatterTag: PersonFormatterTag {
switch displayModeSelector.selectedSegmentIndex {
case 0:
return .MassHeight
default:
return .EyesHair
}
}
}
@@ -0,0 +1,71 @@
//
// FetchableTrait.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
protocol FetchableTrait: class {
typealias ObjectType
var objects: [ObjectType]? { get set }
var batchRequestID: Int { get set }
var tableView: UITableView! { get }
func fetchIDs(completion: [Int] -> Void)
func fetchOne(id: Int, completion: ObjectType? -> Void)
var fetchProgress: (current: Int, total: Int?) { get set }
}
extension FetchableTrait {
func loadObjects(objectIDs: [Int]) {
self.batchRequestID += 1
let batch = self.batchRequestID
objects?.removeAll()
fetchProgress = (0,objectIDs.count)
for objectID in objectIDs {
fetchOne(objectID) { (object: ObjectType?) in
// Exit if we failed to retrive an object for this ID, or if the request
// should be ignored because a new batch request has been started since
guard let object = object where batch == self.batchRequestID else { return }
if self.objects == nil { self.objects = [] }
self.objects?.append(object)
self.fetchProgress.current = self.objects?.count ?? 0
self.tableView?.reloadData()
}
}
}
func loadFirstPage() {
self.batchRequestID += 1
let batch = self.batchRequestID
fetchProgress = (0, nil)
fetchIDs() { objectIDs in
guard batch == self.batchRequestID else { return }
self.loadObjects(objectIDs)
}
}
func displayProgressInNavBar(navigationItem: UINavigationItem) {
let text: String
if let total = fetchProgress.total {
if fetchProgress.current == fetchProgress.total {
text = "Done."
} else {
text = "Loading \(fetchProgress.current) / \(total)"
}
} else {
text = "Loading IDs…"
}
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
label.text = text
label.textColor = .grayColor()
label.font = .systemFontOfSize(12)
label.sizeToFit()
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: label)
}
}
@@ -0,0 +1,56 @@
//
// PersonListViewController.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
class PersonListViewController: UITableViewController, FetchableTrait {
var objects: [Person]?
var batchRequestID = 0
func fetchIDs(completion: [Int] -> Void) {
let provider = providerDependencies.resolve() as PersonProviderAPI
return provider.fetchIDs(completion)
}
func fetchOne(personID: Int, completion: Person? -> Void) {
let provider = providerDependencies.resolve(.Int(personID)) as PersonProviderAPI
return provider.fetch(personID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(self.navigationItem)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .StarshipsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? StarshipListViewController,
let person = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.loadObjects(person.starshipIDs)
}
}
extension PersonListViewController {
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = PersonCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
cell.fillWithObject(object)
return cell
}
}
@@ -0,0 +1,59 @@
//
// StarshipListViewController.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
import Dip
class StarshipListViewController : UITableViewController, FetchableTrait {
var objects: [Starship]?
var batchRequestID = 0
private func provider(tag:Int?) -> StarshipProviderAPI {
return providerDependencies.resolve(tag.flatMap { .Int($0) })
}
func fetchIDs(completion: [Int] -> Void) {
provider(nil).fetchIDs(completion)
}
func fetchOne(shipID:Int, completion: Starship? -> Void) {
provider(shipID).fetch(shipID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(self.navigationItem)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .PilotsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? PersonListViewController,
let starship = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.loadObjects(starship.pilotIDs)
}
}
extension StarshipListViewController {
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = StarshipCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
cell.fillWithObject(object)
return cell
}
}
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Main Pilot</string>
<key>height</key>
<integer>175</integer>
<key>mass</key>
<integer>67</integer>
<key>hairColor</key>
<string>Dark</string>
<key>eyeColor</key>
<string>Brown</string>
<key>gender</key>
<string>male</string>
<key>starships</key>
<array>
<integer>0</integer>
<integer>1</integer>
<integer>3</integer>
</array>
</dict>
</array>
</plist>
+3 -3
View File
@@ -1,5 +1,5 @@
PODS:
- Dip (0.1.0)
- Dip (2.0.0)
DEPENDENCIES:
- Dip (from `../`)
@@ -9,6 +9,6 @@ EXTERNAL SOURCES:
:path: ../
SPEC CHECKSUMS:
Dip: c6d545af478b84d3708bf02d986fe687cb3322cc
Dip: ae784a32e584d5c57809b2cdc4fd2f287d075f7a
COCOAPODS: 0.38.2
COCOAPODS: 0.39.0
+4 -4
View File
@@ -1,8 +1,8 @@
{
"name": "Dip",
"version": "0.1.0",
"summary": "A simple Dependency Resolver (Simplified Dependency Injection-like resolution).",
"description": "Dip is a Swift framework to manage your Dependencies between your classes\nin your app.\n\nIt's aimed to be very simple to use while improving testability\nof your app by allowing you to get rid of those sharedInstances and instead\ninject values based on protocol resolution.\n\nDefine your API using a protocol, then ask Dip to resolve this protocol into\nan instance dynamically in your classes. Then your App and your Tests can be\nconfigured to resolve the protocol using a different instance or class so this\nimprove testability by decoupling the API and the concrete class used to implement it.\n\nIt's not real Dependency Injection _per se_, but it's close.",
"version": "2.0.0",
"summary": "A simple Dependency Resolver: Dependency Injection using Protocol resolution.",
"description": "Dip is a Swift framework to manage your Dependencies between your classes\nin your app using Dependency Injection.\n\nIt's aimed to be very simple to use while improving testability\nof your app by allowing you to get rid of those sharedInstances and instead\ninject values based on protocol resolution.\n\nDefine your API using a protocol, then ask Dip to resolve this protocol into\nan instance dynamically in your classes. Then your App and your Tests can be\nconfigured to resolve the protocol using a different instance or class so this\nimprove testability by decoupling the API and the concrete class used to implement it.",
"homepage": "https://github.com/AliSoftware/Dip",
"license": "MIT",
"authors": {
@@ -10,7 +10,7 @@
},
"source": {
"git": "https://github.com/AliSoftware/Dip.git",
"tag": "0.1.0"
"tag": "2.0.0"
},
"social_media_url": "https://twitter.com/aligatr",
"platforms": {
+3 -3
View File
@@ -1,5 +1,5 @@
PODS:
- Dip (0.1.0)
- Dip (2.0.0)
DEPENDENCIES:
- Dip (from `../`)
@@ -9,6 +9,6 @@ EXTERNAL SOURCES:
:path: ../
SPEC CHECKSUMS:
Dip: c6d545af478b84d3708bf02d986fe687cb3322cc
Dip: ae784a32e584d5c57809b2cdc4fd2f287d075f7a
COCOAPODS: 0.38.2
COCOAPODS: 0.39.0
+248 -246
View File
@@ -7,93 +7,92 @@
objects = {
/* Begin PBXBuildFile section */
4281B9E4626ED37910E70A6053051095 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2913DD9CC28CEF3EB44C812C80C5C242 /* Foundation.framework */; };
760ED030B3F9BF2B88E1F61BB696AF52 /* Pods-DipTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C6D62EFF728EC883AC33E16BEB08DA /* Pods-DipTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
848961CC560A7BF0C4CCEC7F49AD9D93 /* Dip-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B7737BE94231569FDA05F39555BABA9 /* Dip-dummy.m */; };
A56D11EEC8601D29B20437637A398FBE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2913DD9CC28CEF3EB44C812C80C5C242 /* Foundation.framework */; };
B43CB9F263659669B07655407B2663BD /* Pods-DipSampleApp-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D51085C4F230C1CC04D5C97D5CD181 /* Pods-DipSampleApp-dummy.m */; };
B7AF29D7DFAADCE1D059AB81388DC3A9 /* Dip.swift in Sources */ = {isa = PBXBuildFile; fileRef = E85D8C26DBEA227876D2B6BE49C060A3 /* Dip.swift */; };
B89AA8E9CD649EA8710AC177891DADF5 /* Pods-DipTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = B538A5AA13D8CC5A2FB02B8C7E82ACB7 /* Pods-DipTests-dummy.m */; };
CBC622391FBCC36E48C7E3D295582D5A /* Dip-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8042B4793ED34FF6BB085F959C62C902 /* Dip-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
F71A77F6FC1D19954985C78BC04FFBCE /* Pods-DipSampleApp-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BB9324BB13F4127B03E00DAB78DF3D75 /* Pods-DipSampleApp-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
F8BB3BC94ED3830270E0447B6BA4D12D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2913DD9CC28CEF3EB44C812C80C5C242 /* Foundation.framework */; };
233F81BF5C5FCE081EE3E4963D0B28CD /* Pods-DipSampleApp-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6F865EBD27FE4416E8655E73F7426 /* Pods-DipSampleApp-dummy.m */; };
3E5EF2244E6759BDB00BF6F862FFAD43 /* Dip-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D1A0DC92D3A4A2B32D1B6094DECDA3 /* Dip-dummy.m */; };
598949CC3DD0DD2142DFA9759D331DB6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E4E89230EF59BC255123B67864ACF77 /* Foundation.framework */; };
73DFA9D2D6721ED2BF48E815083FC935 /* Dip.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1855646D8AC0B232E538D845A7894FF /* Dip.swift */; };
774AC175C524A1E16D01BB9CF19651ED /* Pods-DipTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FDAF80E63D5379C5D67B2C5D37CB44 /* Pods-DipTests-dummy.m */; };
8FB62E6448665FAB1B4B40278A9C18B3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E4E89230EF59BC255123B67864ACF77 /* Foundation.framework */; };
92915F15583230B1CF7E9FAB6FFD5817 /* Dip-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F68496928C5CF49172AFF11B37314C7 /* Dip-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
CE06FE77C65C0BE8BDD6AFB33EAD328F /* Pods-DipSampleApp-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = ACEDE7C6DC726F30DC3F36A7ECD7A8C2 /* Pods-DipSampleApp-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
DF187AAE55CEA68761E21B080E2C2CF2 /* Pods-DipTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 88B21BAF0A10E4BCDFF1F69039F04287 /* Pods-DipTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
F8D681A620B7540C44E9B51BD381C514 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E4E89230EF59BC255123B67864ACF77 /* Foundation.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
717E8357C15C9EC952989F1892DAADD9 /* PBXContainerItemProxy */ = {
62848E69B71441AB05941E7E2F09E1D8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
proxyType = 1;
remoteGlobalIDString = 61B2C099D2823B76EB65B5ECC8B08934;
remoteGlobalIDString = 28230D259635091F92F106AA282AA138;
remoteInfo = Dip;
};
E1543D580D5FE849EA4540C35848C670 /* PBXContainerItemProxy */ = {
F9BC91C90262AF7A128076332A48985F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
proxyType = 1;
remoteGlobalIDString = 61B2C099D2823B76EB65B5ECC8B08934;
remoteGlobalIDString = 28230D259635091F92F106AA282AA138;
remoteInfo = Dip;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
040E6767354650F6353098E4EB50B3F7 /* Pods-DipSampleApp.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = "Pods-DipSampleApp.modulemap"; sourceTree = "<group>"; };
08FDAF80E63D5379C5D67B2C5D37CB44 /* Pods-DipTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-DipTests-dummy.m"; sourceTree = "<group>"; };
093DB70F67DB4E609AB442CBB509D4E7 /* Pods-DipTests-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-DipTests-resources.sh"; sourceTree = "<group>"; };
17BD92E9BBD2033629156ED61085C674 /* Dip.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Dip.xcconfig; sourceTree = "<group>"; };
2913DD9CC28CEF3EB44C812C80C5C242 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
2DA289A9786072EC94A069BF0205D4D6 /* Dip-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Dip-prefix.pch"; sourceTree = "<group>"; };
3B7737BE94231569FDA05F39555BABA9 /* Dip-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Dip-dummy.m"; sourceTree = "<group>"; };
2F6C88DA4612709E46E6E64B8DE3DF7B /* Pods-DipTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipTests.debug.xcconfig"; sourceTree = "<group>"; };
3BFEC463C4346DFBB40CFD331E7B8C8C /* Pods-DipSampleApp-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-DipSampleApp-acknowledgements.plist"; sourceTree = "<group>"; };
3E4E89230EF59BC255123B67864ACF77 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
4AC7412F56C556428F0902BDB2B9CC74 /* Pods-DipSampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipSampleApp.debug.xcconfig"; sourceTree = "<group>"; };
4D03528B91AE7D78A28CE55BADFA6159 /* Pods-DipTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-DipTests-acknowledgements.plist"; sourceTree = "<group>"; };
53E603F956BC0848C3DC16E858DAA805 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
56CC73CE7812C91DDB29DC2C84CE562F /* Dip-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Dip-Private.xcconfig"; sourceTree = "<group>"; };
6177EEC55F08DE3EBAB9A7AFFB99FA26 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
649D66F1DA814B5F17F49CA0D5948332 /* Pods_DipTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
65517CECF14CA488E474611D4E6C8A28 /* Pods_DipSampleApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipSampleApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6571AF80F9340C8BBB03E41828B56DAE /* Pods-DipSampleApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipSampleApp.release.xcconfig"; sourceTree = "<group>"; };
75D51085C4F230C1CC04D5C97D5CD181 /* Pods-DipSampleApp-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-DipSampleApp-dummy.m"; sourceTree = "<group>"; };
7C0F27E74B4689101CF66C46839222CA /* Pods-DipSampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipSampleApp.debug.xcconfig"; sourceTree = "<group>"; };
8042B4793ED34FF6BB085F959C62C902 /* Dip-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Dip-umbrella.h"; sourceTree = "<group>"; };
865E74B4F963E602B5B976F7D5FFAA0A /* Dip.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = Dip.modulemap; sourceTree = "<group>"; };
9B1020199AD13F9A6B345D4DA93D8FF0 /* Pods-DipTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipTests.release.xcconfig"; sourceTree = "<group>"; };
551D96FB45D8D47702C68C545344BB55 /* Dip-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Dip-prefix.pch"; sourceTree = "<group>"; };
6418C112ABDD19D3EF1DD98DB3019F05 /* Pods_DipTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6DC6F865EBD27FE4416E8655E73F7426 /* Pods-DipSampleApp-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-DipSampleApp-dummy.m"; sourceTree = "<group>"; };
88B21BAF0A10E4BCDFF1F69039F04287 /* Pods-DipTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-DipTests-umbrella.h"; sourceTree = "<group>"; };
8A5334FC48EF0DBABDE182FB6C1E6C3D /* Pods_DipSampleApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipSampleApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
98D1A0DC92D3A4A2B32D1B6094DECDA3 /* Dip-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Dip-dummy.m"; sourceTree = "<group>"; };
9F68496928C5CF49172AFF11B37314C7 /* Dip-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Dip-umbrella.h"; sourceTree = "<group>"; };
A37235974396D8B3A4A2163B9FAF0328 /* Pods-DipSampleApp-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-DipSampleApp-resources.sh"; sourceTree = "<group>"; };
ACEDE7C6DC726F30DC3F36A7ECD7A8C2 /* Pods-DipSampleApp-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-DipSampleApp-umbrella.h"; sourceTree = "<group>"; };
AF0EA8CE3EB9D052ABA91BBDF5935932 /* Pods-DipSampleApp-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-DipSampleApp-frameworks.sh"; sourceTree = "<group>"; };
B13AB9998F2CB1AA813B9AB7A6851FBA /* Pods-DipTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-DipTests-frameworks.sh"; sourceTree = "<group>"; };
B538A5AA13D8CC5A2FB02B8C7E82ACB7 /* Pods-DipTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-DipTests-dummy.m"; sourceTree = "<group>"; };
BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
BB9324BB13F4127B03E00DAB78DF3D75 /* Pods-DipSampleApp-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-DipSampleApp-umbrella.h"; sourceTree = "<group>"; };
CFFD5CBC2BC2688B5A6735AF757D7A13 /* Pods-DipTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipTests.debug.xcconfig"; sourceTree = "<group>"; };
D5CB81F4D94CD0DC953C46A26FA193D9 /* Dip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BDD421F6E0B38080BCB472073DA141EF /* Dip.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = Dip.modulemap; sourceTree = "<group>"; };
C9D3BEDF370AEED8CE8D3838C4F8BCB1 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D1855646D8AC0B232E538D845A7894FF /* Dip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Dip.swift; sourceTree = "<group>"; };
D431A88F8543B8C4079050ACDD792D51 /* Dip.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Dip.xcconfig; sourceTree = "<group>"; };
D70F3F84928AF07F304E2A78BED54F5E /* Pods-DipTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipTests.release.xcconfig"; sourceTree = "<group>"; };
DD7CF98DF0A99296E41AF2D9C3B473F9 /* Pods-DipTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-DipTests-acknowledgements.markdown"; sourceTree = "<group>"; };
DDDDDD06DF5540C55DA4B0C74E1EC511 /* Pods-DipTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = "Pods-DipTests.modulemap"; sourceTree = "<group>"; };
E1A14DC75595E6F6652CBCCE34EF2BC2 /* Dip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E2C25F36DD7F27E8BA0BDFFF808541A7 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E6C6D62EFF728EC883AC33E16BEB08DA /* Pods-DipTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-DipTests-umbrella.h"; sourceTree = "<group>"; };
E85D8C26DBEA227876D2B6BE49C060A3 /* Dip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Dip.swift; sourceTree = "<group>"; };
F5067212B9AFB98F7CCBC7151A60A220 /* Pods-DipSampleApp-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-DipSampleApp-acknowledgements.markdown"; sourceTree = "<group>"; };
FCA73F622E211B8366C7D190CE804EA5 /* Pods-DipSampleApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-DipSampleApp.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
139BA28D38AF67B41F2223A714A1DE43 /* Frameworks */ = {
7054D0CB6C690B6BE41E609084CA0958 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A56D11EEC8601D29B20437637A398FBE /* Foundation.framework in Frameworks */,
8FB62E6448665FAB1B4B40278A9C18B3 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7A84D2955EF7C71F5E6AF48E447815A1 /* Frameworks */ = {
9E15208AD5F4351018028853ABA69EB9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4281B9E4626ED37910E70A6053051095 /* Foundation.framework in Frameworks */,
F8D681A620B7540C44E9B51BD381C514 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
FC3CB05065376B8016B026FD865ABAC0 /* Frameworks */ = {
ED999B179D5C9983F80D581113B9D018 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F8BB3BC94ED3830270E0447B6BA4D12D /* Foundation.framework in Frameworks */,
598949CC3DD0DD2142DFA9759D331DB6 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -107,53 +106,44 @@
DDDDDD06DF5540C55DA4B0C74E1EC511 /* Pods-DipTests.modulemap */,
DD7CF98DF0A99296E41AF2D9C3B473F9 /* Pods-DipTests-acknowledgements.markdown */,
4D03528B91AE7D78A28CE55BADFA6159 /* Pods-DipTests-acknowledgements.plist */,
B538A5AA13D8CC5A2FB02B8C7E82ACB7 /* Pods-DipTests-dummy.m */,
08FDAF80E63D5379C5D67B2C5D37CB44 /* Pods-DipTests-dummy.m */,
B13AB9998F2CB1AA813B9AB7A6851FBA /* Pods-DipTests-frameworks.sh */,
093DB70F67DB4E609AB442CBB509D4E7 /* Pods-DipTests-resources.sh */,
E6C6D62EFF728EC883AC33E16BEB08DA /* Pods-DipTests-umbrella.h */,
CFFD5CBC2BC2688B5A6735AF757D7A13 /* Pods-DipTests.debug.xcconfig */,
9B1020199AD13F9A6B345D4DA93D8FF0 /* Pods-DipTests.release.xcconfig */,
88B21BAF0A10E4BCDFF1F69039F04287 /* Pods-DipTests-umbrella.h */,
2F6C88DA4612709E46E6E64B8DE3DF7B /* Pods-DipTests.debug.xcconfig */,
D70F3F84928AF07F304E2A78BED54F5E /* Pods-DipTests.release.xcconfig */,
);
name = "Pods-DipTests";
path = "Target Support Files/Pods-DipTests";
sourceTree = "<group>";
};
331BF982C22B5DA66B25F742D01C5F7D /* Dip */ = {
3A648B4C2102C68BD49258688BF389CC /* Products */ = {
isa = PBXGroup;
children = (
FAEF7893A179133A40296BA56F7E8846 /* Sources */,
7BF12AE4821DF0409A5DD1E494A23CB0 /* Support Files */,
E1A14DC75595E6F6652CBCCE34EF2BC2 /* Dip.framework */,
8A5334FC48EF0DBABDE182FB6C1E6C3D /* Pods_DipSampleApp.framework */,
6418C112ABDD19D3EF1DD98DB3019F05 /* Pods_DipTests.framework */,
);
name = Dip;
path = ../..;
name = Products;
sourceTree = "<group>";
};
46E7572EB1611944AB13E50F656187E9 /* Development Pods */ = {
isa = PBXGroup;
children = (
331BF982C22B5DA66B25F742D01C5F7D /* Dip */,
C40734A4DEEFC0C72EE1D1BCF19DD769 /* Dip */,
);
name = "Development Pods";
sourceTree = "<group>";
};
53F661C0CA7190D2CF05023FB33D61E4 /* iOS */ = {
480A2A3476910EE7306AD0610F482D25 /* Support Files */ = {
isa = PBXGroup;
children = (
2913DD9CC28CEF3EB44C812C80C5C242 /* Foundation.framework */,
);
name = iOS;
sourceTree = "<group>";
};
7BF12AE4821DF0409A5DD1E494A23CB0 /* Support Files */ = {
isa = PBXGroup;
children = (
865E74B4F963E602B5B976F7D5FFAA0A /* Dip.modulemap */,
17BD92E9BBD2033629156ED61085C674 /* Dip.xcconfig */,
56CC73CE7812C91DDB29DC2C84CE562F /* Dip-Private.xcconfig */,
3B7737BE94231569FDA05F39555BABA9 /* Dip-dummy.m */,
2DA289A9786072EC94A069BF0205D4D6 /* Dip-prefix.pch */,
8042B4793ED34FF6BB085F959C62C902 /* Dip-umbrella.h */,
6177EEC55F08DE3EBAB9A7AFFB99FA26 /* Info.plist */,
BDD421F6E0B38080BCB472073DA141EF /* Dip.modulemap */,
D431A88F8543B8C4079050ACDD792D51 /* Dip.xcconfig */,
98D1A0DC92D3A4A2B32D1B6094DECDA3 /* Dip-dummy.m */,
551D96FB45D8D47702C68C545344BB55 /* Dip-prefix.pch */,
9F68496928C5CF49172AFF11B37314C7 /* Dip-umbrella.h */,
C9D3BEDF370AEED8CE8D3838C4F8BCB1 /* Info.plist */,
);
name = "Support Files";
path = "Example/Pods/Target Support Files/Dip";
@@ -165,7 +155,7 @@
BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */,
46E7572EB1611944AB13E50F656187E9 /* Development Pods */,
BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */,
CCA510CFBEA2D207524CDA0D73C3B561 /* Products */,
3A648B4C2102C68BD49258688BF389CC /* Products */,
A9D31FC7B7A14D2E4651A6C66A1A86EC /* Targets Support Files */,
);
sourceTree = "<group>";
@@ -182,19 +172,35 @@
BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */ = {
isa = PBXGroup;
children = (
53F661C0CA7190D2CF05023FB33D61E4 /* iOS */,
BF6342C8B29F4CEEA088EFF7AB4DE362 /* iOS */,
);
name = Frameworks;
sourceTree = "<group>";
};
CCA510CFBEA2D207524CDA0D73C3B561 /* Products */ = {
BF6342C8B29F4CEEA088EFF7AB4DE362 /* iOS */ = {
isa = PBXGroup;
children = (
D5CB81F4D94CD0DC953C46A26FA193D9 /* Dip.framework */,
65517CECF14CA488E474611D4E6C8A28 /* Pods_DipSampleApp.framework */,
649D66F1DA814B5F17F49CA0D5948332 /* Pods_DipTests.framework */,
3E4E89230EF59BC255123B67864ACF77 /* Foundation.framework */,
);
name = Products;
name = iOS;
sourceTree = "<group>";
};
C40734A4DEEFC0C72EE1D1BCF19DD769 /* Dip */ = {
isa = PBXGroup;
children = (
CF3CAD3FD76F762243056FAE7CFCDD9D /* Sources */,
480A2A3476910EE7306AD0610F482D25 /* Support Files */,
);
name = Dip;
path = ../..;
sourceTree = "<group>";
};
CF3CAD3FD76F762243056FAE7CFCDD9D /* Sources */ = {
isa = PBXGroup;
children = (
D1855646D8AC0B232E538D845A7894FF /* Dip.swift */,
);
path = Sources;
sourceTree = "<group>";
};
E6EDC7112547C1E567413310A74E6AB2 /* Pods-DipSampleApp */ = {
@@ -204,80 +210,54 @@
040E6767354650F6353098E4EB50B3F7 /* Pods-DipSampleApp.modulemap */,
F5067212B9AFB98F7CCBC7151A60A220 /* Pods-DipSampleApp-acknowledgements.markdown */,
3BFEC463C4346DFBB40CFD331E7B8C8C /* Pods-DipSampleApp-acknowledgements.plist */,
75D51085C4F230C1CC04D5C97D5CD181 /* Pods-DipSampleApp-dummy.m */,
6DC6F865EBD27FE4416E8655E73F7426 /* Pods-DipSampleApp-dummy.m */,
AF0EA8CE3EB9D052ABA91BBDF5935932 /* Pods-DipSampleApp-frameworks.sh */,
A37235974396D8B3A4A2163B9FAF0328 /* Pods-DipSampleApp-resources.sh */,
BB9324BB13F4127B03E00DAB78DF3D75 /* Pods-DipSampleApp-umbrella.h */,
7C0F27E74B4689101CF66C46839222CA /* Pods-DipSampleApp.debug.xcconfig */,
6571AF80F9340C8BBB03E41828B56DAE /* Pods-DipSampleApp.release.xcconfig */,
ACEDE7C6DC726F30DC3F36A7ECD7A8C2 /* Pods-DipSampleApp-umbrella.h */,
4AC7412F56C556428F0902BDB2B9CC74 /* Pods-DipSampleApp.debug.xcconfig */,
FCA73F622E211B8366C7D190CE804EA5 /* Pods-DipSampleApp.release.xcconfig */,
);
name = "Pods-DipSampleApp";
path = "Target Support Files/Pods-DipSampleApp";
sourceTree = "<group>";
};
FAEF7893A179133A40296BA56F7E8846 /* Sources */ = {
isa = PBXGroup;
children = (
E85D8C26DBEA227876D2B6BE49C060A3 /* Dip.swift */,
);
path = Sources;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
20D2FAD8897F05F0F21B6E88F602A8B1 /* Headers */ = {
91E0558A996F1C7D67CEF7650719B736 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
CBC622391FBCC36E48C7E3D295582D5A /* Dip-umbrella.h in Headers */,
92915F15583230B1CF7E9FAB6FFD5817 /* Dip-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
757551662869B25EE206B19D53CC8F29 /* Headers */ = {
BBAC4F3AB5D36D3D0D5D75D8B850C13E /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
760ED030B3F9BF2B88E1F61BB696AF52 /* Pods-DipTests-umbrella.h in Headers */,
CE06FE77C65C0BE8BDD6AFB33EAD328F /* Pods-DipSampleApp-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8F49CC8E1874111D7EF4D173435D7A24 /* Headers */ = {
DD721702CA080CE29A0491036618E6FD /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
F71A77F6FC1D19954985C78BC04FFBCE /* Pods-DipSampleApp-umbrella.h in Headers */,
DF187AAE55CEA68761E21B080E2C2CF2 /* Pods-DipTests-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
12D3E41651D0F284852A4D526F3256AB /* Pods-DipTests */ = {
28230D259635091F92F106AA282AA138 /* Dip */ = {
isa = PBXNativeTarget;
buildConfigurationList = D7E091A3E6CE5EC7EA78C29D8A21CA70 /* Build configuration list for PBXNativeTarget "Pods-DipTests" */;
buildConfigurationList = 31CFDCC9535978BB70FDA95D6D357629 /* Build configuration list for PBXNativeTarget "Dip" */;
buildPhases = (
AAA3A1408B53FD669A84EBE81D8355D0 /* Sources */,
7A84D2955EF7C71F5E6AF48E447815A1 /* Frameworks */,
757551662869B25EE206B19D53CC8F29 /* Headers */,
);
buildRules = (
);
dependencies = (
59D193CC66DB380EE84635F4E2991CAF /* PBXTargetDependency */,
);
name = "Pods-DipTests";
productName = "Pods-DipTests";
productReference = 649D66F1DA814B5F17F49CA0D5948332 /* Pods_DipTests.framework */;
productType = "com.apple.product-type.framework";
};
61B2C099D2823B76EB65B5ECC8B08934 /* Dip */ = {
isa = PBXNativeTarget;
buildConfigurationList = CA02FBD0A4DFAC6631999B9E5DEAA891 /* Build configuration list for PBXNativeTarget "Dip" */;
buildPhases = (
27301CA68EAB0531B3E302342BE6B391 /* Sources */,
139BA28D38AF67B41F2223A714A1DE43 /* Frameworks */,
20D2FAD8897F05F0F21B6E88F602A8B1 /* Headers */,
6A1130E1D8B20BCD2F3070FD7541D03E /* Sources */,
9E15208AD5F4351018028853ABA69EB9 /* Frameworks */,
91E0558A996F1C7D67CEF7650719B736 /* Headers */,
);
buildRules = (
);
@@ -285,25 +265,43 @@
);
name = Dip;
productName = Dip;
productReference = D5CB81F4D94CD0DC953C46A26FA193D9 /* Dip.framework */;
productReference = E1A14DC75595E6F6652CBCCE34EF2BC2 /* Dip.framework */;
productType = "com.apple.product-type.framework";
};
F588C5114410BDD4CA3AF7BF16AF6FC8 /* Pods-DipSampleApp */ = {
3A53F07A7DBB3101BFCAD512E679F62C /* Pods-DipSampleApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9ECD5CC6E806AF1E5D7F66D29B6DDADD /* Build configuration list for PBXNativeTarget "Pods-DipSampleApp" */;
buildConfigurationList = B70E7A5902F5B0D610680BC908B731F3 /* Build configuration list for PBXNativeTarget "Pods-DipSampleApp" */;
buildPhases = (
811AA0482F2A12B79AFCB6A2C9AFA4A1 /* Sources */,
FC3CB05065376B8016B026FD865ABAC0 /* Frameworks */,
8F49CC8E1874111D7EF4D173435D7A24 /* Headers */,
A943C34198589805B647072D0565220C /* Sources */,
ED999B179D5C9983F80D581113B9D018 /* Frameworks */,
BBAC4F3AB5D36D3D0D5D75D8B850C13E /* Headers */,
);
buildRules = (
);
dependencies = (
E87C16215529DC10230F8D3773193425 /* PBXTargetDependency */,
394A3171C70875A58CBC5E1A1DC019D7 /* PBXTargetDependency */,
);
name = "Pods-DipSampleApp";
productName = "Pods-DipSampleApp";
productReference = 65517CECF14CA488E474611D4E6C8A28 /* Pods_DipSampleApp.framework */;
productReference = 8A5334FC48EF0DBABDE182FB6C1E6C3D /* Pods_DipSampleApp.framework */;
productType = "com.apple.product-type.framework";
};
A282C21E8EC965D4836B3AECBB21F499 /* Pods-DipTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 35DD63728C36940D0AE695EF42CC6F57 /* Build configuration list for PBXNativeTarget "Pods-DipTests" */;
buildPhases = (
62BE8684290E236F96D180ADDAB07160 /* Sources */,
7054D0CB6C690B6BE41E609084CA0958 /* Frameworks */,
DD721702CA080CE29A0491036618E6FD /* Headers */,
);
buildRules = (
);
dependencies = (
5541F443020F2B10F9A04FE23958A4C6 /* PBXTargetDependency */,
);
name = "Pods-DipTests";
productName = "Pods-DipTests";
productReference = 6418C112ABDD19D3EF1DD98DB3019F05 /* Pods_DipTests.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
@@ -323,122 +321,64 @@
en,
);
mainGroup = 7DB346D0F39D3F0E887471402A8071AB;
productRefGroup = CCA510CFBEA2D207524CDA0D73C3B561 /* Products */;
productRefGroup = 3A648B4C2102C68BD49258688BF389CC /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
61B2C099D2823B76EB65B5ECC8B08934 /* Dip */,
F588C5114410BDD4CA3AF7BF16AF6FC8 /* Pods-DipSampleApp */,
12D3E41651D0F284852A4D526F3256AB /* Pods-DipTests */,
28230D259635091F92F106AA282AA138 /* Dip */,
3A53F07A7DBB3101BFCAD512E679F62C /* Pods-DipSampleApp */,
A282C21E8EC965D4836B3AECBB21F499 /* Pods-DipTests */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
27301CA68EAB0531B3E302342BE6B391 /* Sources */ = {
62BE8684290E236F96D180ADDAB07160 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
848961CC560A7BF0C4CCEC7F49AD9D93 /* Dip-dummy.m in Sources */,
B7AF29D7DFAADCE1D059AB81388DC3A9 /* Dip.swift in Sources */,
774AC175C524A1E16D01BB9CF19651ED /* Pods-DipTests-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
811AA0482F2A12B79AFCB6A2C9AFA4A1 /* Sources */ = {
6A1130E1D8B20BCD2F3070FD7541D03E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B43CB9F263659669B07655407B2663BD /* Pods-DipSampleApp-dummy.m in Sources */,
3E5EF2244E6759BDB00BF6F862FFAD43 /* Dip-dummy.m in Sources */,
73DFA9D2D6721ED2BF48E815083FC935 /* Dip.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
AAA3A1408B53FD669A84EBE81D8355D0 /* Sources */ = {
A943C34198589805B647072D0565220C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B89AA8E9CD649EA8710AC177891DADF5 /* Pods-DipTests-dummy.m in Sources */,
233F81BF5C5FCE081EE3E4963D0B28CD /* Pods-DipSampleApp-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
59D193CC66DB380EE84635F4E2991CAF /* PBXTargetDependency */ = {
394A3171C70875A58CBC5E1A1DC019D7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Dip;
target = 61B2C099D2823B76EB65B5ECC8B08934 /* Dip */;
targetProxy = 717E8357C15C9EC952989F1892DAADD9 /* PBXContainerItemProxy */;
target = 28230D259635091F92F106AA282AA138 /* Dip */;
targetProxy = 62848E69B71441AB05941E7E2F09E1D8 /* PBXContainerItemProxy */;
};
E87C16215529DC10230F8D3773193425 /* PBXTargetDependency */ = {
5541F443020F2B10F9A04FE23958A4C6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Dip;
target = 61B2C099D2823B76EB65B5ECC8B08934 /* Dip */;
targetProxy = E1543D580D5FE849EA4540C35848C670 /* PBXContainerItemProxy */;
target = 28230D259635091F92F106AA282AA138 /* Dip */;
targetProxy = F9BC91C90262AF7A128076332A48985F /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
179C38BF617A5FDB3138E3FBBCFBCF96 /* Debug */ = {
1473D344CDCA306DE692B6341E997B38 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 56CC73CE7812C91DDB29DC2C84CE562F /* Dip-Private.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 0.1.0;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 0.1.0;
DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)";
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_PREFIX_HEADER = "Target Support Files/Dip/Dip-prefix.pch";
INFOPLIST_FILE = "Target Support Files/Dip/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = "Target Support Files/Dip/Dip.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_NAME = Dip;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
1858E18D65A8B61BEAE72BD61ED409B9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7C0F27E74B4689101CF66C46839222CA /* Pods-DipSampleApp.debug.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
INFOPLIST_FILE = "Target Support Files/Pods-DipSampleApp/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = "Target Support Files/Pods-DipSampleApp/Pods-DipSampleApp.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_NAME = Pods_DipSampleApp;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
530E51D69A65177A0CB8BA9337627948 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9B1020199AD13F9A6B345D4DA93D8FF0 /* Pods-DipTests.release.xcconfig */;
baseConfigurationReference = 2F6C88DA4612709E46E6E64B8DE3DF7B /* Pods-DipTests.debug.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
@@ -451,23 +391,25 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-DipTests/Pods-DipTests.modulemap";
MTL_ENABLE_DEBUG_INFO = NO;
MTL_ENABLE_DEBUG_INFO = YES;
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_NAME = Pods_DipTests;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
name = Debug;
};
956BB501D5CF8EBD179183A55861D46E /* Release */ = {
6A72424D270F509461FC20CD059294D4 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6571AF80F9340C8BBB03E41828B56DAE /* Pods-DipSampleApp.release.xcconfig */;
baseConfigurationReference = D431A88F8543B8C4079050ACDD792D51 /* Dip.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
@@ -476,35 +418,6 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
INFOPLIST_FILE = "Target Support Files/Pods-DipSampleApp/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = "Target Support Files/Pods-DipSampleApp/Pods-DipSampleApp.modulemap";
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_NAME = Pods_DipSampleApp;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
9867AC43F4246CE452AFD55B859928CC /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 56CC73CE7812C91DDB29DC2C84CE562F /* Dip-Private.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 0.1.0;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 0.1.0;
DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)";
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_PREFIX_HEADER = "Target Support Files/Dip/Dip-prefix.pch";
INFOPLIST_FILE = "Target Support Files/Dip/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -521,6 +434,37 @@
};
name = Release;
};
78F0B5FBEADFB5A705557C10BE04C413 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 4AC7412F56C556428F0902BDB2B9CC74 /* Pods-DipSampleApp.debug.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
INFOPLIST_FILE = "Target Support Files/Pods-DipSampleApp/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-DipSampleApp/Pods-DipSampleApp.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_NAME = Pods_DipSampleApp;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
A70CDAD61F90AC503C7D04CC22DA2923 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -560,9 +504,67 @@
};
name = Debug;
};
A72E6B5B0A3D3E28381E5C0A7A93C0A5 /* Debug */ = {
B974ED11B24EB1E4C3321062F24469F4 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = CFFD5CBC2BC2688B5A6735AF757D7A13 /* Pods-DipTests.debug.xcconfig */;
baseConfigurationReference = D431A88F8543B8C4079050ACDD792D51 /* Dip.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_PREFIX_HEADER = "Target Support Files/Dip/Dip-prefix.pch";
INFOPLIST_FILE = "Target Support Files/Dip/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = "Target Support Files/Dip/Dip.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_NAME = Dip;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
CBDDB14779D5F8C01DB8F4A9A013509C /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = FCA73F622E211B8366C7D190CE804EA5 /* Pods-DipSampleApp.release.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
INFOPLIST_FILE = "Target Support Files/Pods-DipSampleApp/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-DipSampleApp/Pods-DipSampleApp.modulemap";
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_NAME = Pods_DipSampleApp;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
F1BFBC0693AAA13A7013B018CED4126C /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D70F3F84928AF07F304E2A78BED54F5E /* Pods-DipTests.release.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
@@ -575,20 +577,20 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-DipTests/Pods-DipTests.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_NAME = Pods_DipTests;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
name = Release;
};
FB45FFD90572718D82AB9092B750F0CA /* Release */ = {
isa = XCBuildConfiguration;
@@ -636,29 +638,29 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9ECD5CC6E806AF1E5D7F66D29B6DDADD /* Build configuration list for PBXNativeTarget "Pods-DipSampleApp" */ = {
31CFDCC9535978BB70FDA95D6D357629 /* Build configuration list for PBXNativeTarget "Dip" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1858E18D65A8B61BEAE72BD61ED409B9 /* Debug */,
956BB501D5CF8EBD179183A55861D46E /* Release */,
B974ED11B24EB1E4C3321062F24469F4 /* Debug */,
6A72424D270F509461FC20CD059294D4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CA02FBD0A4DFAC6631999B9E5DEAA891 /* Build configuration list for PBXNativeTarget "Dip" */ = {
35DD63728C36940D0AE695EF42CC6F57 /* Build configuration list for PBXNativeTarget "Pods-DipTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
179C38BF617A5FDB3138E3FBBCFBCF96 /* Debug */,
9867AC43F4246CE452AFD55B859928CC /* Release */,
1473D344CDCA306DE692B6341E997B38 /* Debug */,
F1BFBC0693AAA13A7013B018CED4126C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D7E091A3E6CE5EC7EA78C29D8A21CA70 /* Build configuration list for PBXNativeTarget "Pods-DipTests" */ = {
B70E7A5902F5B0D610680BC908B731F3 /* Build configuration list for PBXNativeTarget "Pods-DipSampleApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A72E6B5B0A3D3E28381E5C0A7A93C0A5 /* Debug */,
530E51D69A65177A0CB8BA9337627948 /* Release */,
78F0B5FBEADFB5A705557C10BE04C413 /* Debug */,
CBDDB14779D5F8C01DB8F4A9A013509C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -7,33 +7,30 @@
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "61B2C099D2823B76EB65B5ECC8B08934"
BuildableName = "Dip.framework"
BlueprintName = "Dip"
ReferencedContainer = "container:Pods.xcodeproj">
BuildableIdentifier = 'primary'
BlueprintIdentifier = '0CFBD42E9A9E0A9CBD1C8DD7'
BlueprintName = 'Dip'
ReferencedContainer = 'container:Pods.xcodeproj'
BuildableName = 'Dip.framework'>
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
@@ -41,25 +38,17 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "61B2C099D2823B76EB65B5ECC8B08934"
BuildableName = "Dip.framework"
BlueprintName = "Dip"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
@@ -1,6 +0,0 @@
#include "Dip.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Dip" "${PODS_ROOT}/Headers/Public"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_ROOT = ${SRCROOT}
SKIP_INSTALL = YES
+5
View File
@@ -0,0 +1,5 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Dip" "${PODS_ROOT}/Headers/Public"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_ROOT = ${SRCROOT}
SKIP_INSTALL = YES
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.1.0</string>
<string>2.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -10,8 +10,10 @@ install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
else
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
@@ -25,19 +27,31 @@ install_framework()
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries
local basename
basename="$(basename "$1" | sed -E s/\\..+// && exit ${PIPESTATUS[0]})"
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/${basename}.framework/${basename}" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
fi
}
# Signs a framework with the provided identity
@@ -50,10 +64,28 @@ code_sign_if_enabled() {
fi
}
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
stripped=""
for arch in $archs; do
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
}
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework 'Pods-DipSampleApp/Dip.framework'
install_framework "Pods-DipSampleApp/Dip.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework 'Pods-DipSampleApp/Dip.framework'
install_framework "Pods-DipSampleApp/Dip.framework"
fi
@@ -60,7 +60,7 @@ install_resource()
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]]; then
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
@@ -1,3 +1,4 @@
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Dip.framework/Headers"
@@ -1,3 +1,4 @@
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Dip.framework/Headers"
@@ -10,8 +10,10 @@ install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
else
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
@@ -25,19 +27,31 @@ install_framework()
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries
local basename
basename="$(basename "$1" | sed -E s/\\..+// && exit ${PIPESTATUS[0]})"
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/${basename}.framework/${basename}" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
fi
}
# Signs a framework with the provided identity
@@ -50,10 +64,28 @@ code_sign_if_enabled() {
fi
}
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
stripped=""
for arch in $archs; do
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
}
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework 'Pods-DipTests/Dip.framework'
install_framework "Pods-DipTests/Dip.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework 'Pods-DipTests/Dip.framework'
install_framework "Pods-DipTests/Dip.framework"
fi
@@ -60,7 +60,7 @@ install_resource()
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]]; then
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
@@ -1,3 +1,4 @@
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Dip.framework/Headers"
@@ -1,3 +1,4 @@
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Dip.framework/Headers"
+37
View File
@@ -0,0 +1,37 @@
//
// NetworkMock.swift
// Dip
//
// Created by Olivier Halligon on 11/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
var wsDependencies = DependencyContainer()
// MARK: - Mock object used for tests
struct NetworkMock : NetworkLayer {
let fakeData: NSData?
init(json: AnyObject) {
do {
fakeData = try NSJSONSerialization.dataWithJSONObject(json, options: [])
} catch {
fakeData = nil
}
}
func request(path: String, completion: NetworkResponse -> Void) {
let fakeURL = NSURL(string: "stub://")!.URLByAppendingPathComponent(path)
if let data = fakeData {
let response = NSHTTPURLResponse(URL: fakeURL, statusCode: 200, HTTPVersion: "1.1", headerFields:nil)!
completion(.Success(data, response))
} else {
let response = NSHTTPURLResponse(URL: fakeURL, statusCode: 204, HTTPVersion: "1.1", headerFields:nil)!
completion(.Success(NSData(), response))
}
}
}
@@ -0,0 +1,68 @@
//
// SWAPIPersonProviderTests.swift
// Dip
//
// Created by Olivier Halligon on 11/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import XCTest
import Dip
class SWAPIPersonProviderTests: XCTestCase {
let fakePerson1 = ["name": "John Doe", "mass": "72", "height": "172", "eye_color": "brown", "hair_color": "black", "gender": "male",
"starships": ["stub://starship/7/", "stub://starship/15"], "url": "stub://people/1"]
let fakePerson2 = ["name": "Jane Doe", "mass": "63", "height": "167", "eye_color": "blue", "hair_color": "red", "gender": "female",
"starships": ["stub://starship/11/"], "url": "stub://people/12"]
override func setUp() {
super.setUp()
wsDependencies.reset()
}
func testFetchPersonIDs() {
let mock = NetworkMock(json: ["results": [fakePerson1, fakePerson2]])
wsDependencies.register(WebService.PersonWS.tag, instance: mock as NetworkLayer)
let provider = SWAPIPersonProvider()
provider.fetchIDs { personIDs in
XCTAssertNotNil(personIDs)
XCTAssertEqual(personIDs.count, 2)
XCTAssertEqual(personIDs[0], 1)
XCTAssertEqual(personIDs[1], 12)
}
}
func testFetchOnePerson() {
let mock = NetworkMock(json: fakePerson1)
wsDependencies.register(WebService.PersonWS.tag, instance: mock as NetworkLayer)
let provider = SWAPIPersonProvider()
provider.fetch(1) { person in
XCTAssertNotNil(person)
XCTAssertEqual(person?.name, "John Doe")
XCTAssertEqual(person?.mass, 72)
XCTAssertEqual(person?.height, 172)
XCTAssertEqual(person?.eyeColor, "brown")
XCTAssertEqual(person?.hairColor, "black")
XCTAssertEqual(person?.gender, .Male)
XCTAssertEqual(person?.starshipIDs.count, 2)
XCTAssertEqual(person?.starshipIDs[0], 7)
XCTAssertEqual(person?.starshipIDs[1], 15)
}
}
func testFetchInvalidPerson() {
let json = ["error":"whoops"]
let mock = NetworkMock(json: json)
wsDependencies.register(WebService.PersonWS.tag, instance: mock as NetworkLayer)
let provider = SWAPIPersonProvider()
provider.fetch(12) { person in
XCTAssertNil(person)
}
}
}
@@ -0,0 +1,67 @@
//
// SWAPIStarshipProviderTests.swift
// Dip
//
// Created by Olivier Halligon on 11/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import XCTest
import Dip
class SWAPIStarshipProviderTests: XCTestCase {
let fakeShip1 = ["name": "Falcon", "model": "Fighter", "manufacturer": "Fake Industries", "crew": "7", "passengers": "15",
"pilots": ["stub://people/1/", "stub://people/9"], "url": "stub://starship/4"]
let fakeShip2 = ["name": "Voyager", "model": "Cargo", "manufacturer": "Fake Industries", "crew": "18", "passengers": "150",
"pilots": ["stub://people/2/", "stub://people/3"], "url": "stub://starship/31"]
override func setUp() {
super.setUp()
wsDependencies.reset()
}
func testFetchStarshipIDs() {
let mock = NetworkMock(json: ["results": [fakeShip1, fakeShip2]])
wsDependencies.register(WebService.StarshipWS.tag, instance: mock as NetworkLayer)
let provider = SWAPIStarshipProvider()
provider.fetchIDs { shipIDs in
XCTAssertNotNil(shipIDs)
XCTAssertEqual(shipIDs.count, 2)
XCTAssertEqual(shipIDs[0], 4)
XCTAssertEqual(shipIDs[1], 31)
}
}
func testFetchOneStarship() {
let mock = NetworkMock(json: fakeShip1)
wsDependencies.register(WebService.StarshipWS.tag, instance: mock as NetworkLayer)
let provider = SWAPIStarshipProvider()
provider.fetch(1) { starship in
XCTAssertNotNil(starship)
XCTAssertEqual(starship?.name, "Falcon")
XCTAssertEqual(starship?.model, "Fighter")
XCTAssertEqual(starship?.manufacturer, "Fake Industries")
XCTAssertEqual(starship?.crew, 7)
XCTAssertEqual(starship?.passengers, 15)
XCTAssertNotNil(starship?.pilotIDs)
XCTAssertEqual(starship?.pilotIDs[0], 1)
XCTAssertEqual(starship?.pilotIDs[1], 9)
}
}
func testFetchInvalidStarship() {
let json = ["error":"whoops"]
let mock = NetworkMock(json: json)
wsDependencies.register(WebService.StarshipWS.tag, instance: mock as NetworkLayer)
let provider = SWAPIStarshipProvider()
provider.fetch(12) { starship in
XCTAssertNil(starship)
}
}
}
-89
View File
@@ -1,89 +0,0 @@
import UIKit
import XCTest
import Dip
var dip = DependencyContainer<PersonFormatterTag>()
let p1 = ["name": "John Doe", "mass": "72", "height": "172", "eye_color": "brown", "hair_color": "black"]
let p2 = ["name": "Jane Doe", "mass": "63", "height": "167", "eye_color": "blue", "hair_color": "red"]
class SWAPIWebServiceTests: XCTestCase {
// MARK: - Mock object used for tests
struct NetworkMock : NetworkLayer {
let fakeData: NSData?
init(json: AnyObject) {
do {
fakeData = try NSJSONSerialization.dataWithJSONObject(json, options: [])
} catch {
fakeData = nil
}
}
func fetchURL(url: NSURL, completion: NSData? -> Void) {
completion(fakeData)
}
}
// MARK: - Test Suite
override func setUp() {
super.setUp()
dip.reset()
dip.register(instance: SWAPIPersonFactory() as PersonFactoryAPI)
dip.register(instance: JSONSerializer() as SerializerAPI)
}
func testFetchPersons() {
let mock = NetworkMock(json: ["results":[p1,p2]])
dip.register(instance: mock as NetworkLayer)
let ws = SWAPIWebService()
ws.fetch { persons in
XCTAssertNotNil(persons)
XCTAssertEqual(persons?.count, 2)
XCTAssertEqual(persons?[0].name, "John Doe")
XCTAssertEqual(persons?[0].mass, 72)
XCTAssertEqual(persons?[0].height, 172)
XCTAssertEqual(persons?[0].eyesColor, "brown")
XCTAssertEqual(persons?[0].hairColor, "black")
XCTAssertEqual(persons?[1].name, "Jane Doe")
XCTAssertEqual(persons?[1].mass, 63)
XCTAssertEqual(persons?[1].height, 167)
XCTAssertEqual(persons?[1].eyesColor, "blue")
XCTAssertEqual(persons?[1].hairColor, "red")
}
}
func testFetchOnePerson() {
let mock = NetworkMock(json: p1)
dip.register(instance: mock as NetworkLayer)
let ws = SWAPIWebService()
ws.fetch(1) { person in
XCTAssertNotNil(person)
XCTAssertEqual(person?.name, "John Doe")
XCTAssertEqual(person?.mass, 72)
XCTAssertEqual(person?.height, 172)
XCTAssertEqual(person?.eyesColor, "brown")
XCTAssertEqual(person?.hairColor, "black")
}
}
func testFetchInvalidPerson() {
let json = ["error":"whoops"]
let mock = NetworkMock(json: json)
dip.register(instance: mock as NetworkLayer)
let ws = SWAPIWebService()
ws.fetch(12) { person in
XCTAssertNil(person)
}
}
}
+61 -19
View File
@@ -5,8 +5,8 @@
[![License](https://img.shields.io/cocoapods/l/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Platform](https://img.shields.io/cocoapods/p/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
![Chocolate con churros - San Ginés, Madrid](https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Chocolate_con_churros_-_San_Ginés%2C_Madrid.jpg/160px-Chocolate_con_churros_-_San_Ginés%2C_Madrid.jpg)
_Photo by [Matthew Hine](http://www.flickr.com/photos/75771631@N00), cc-by-2.0_
![Animated Dipping GIF](cinnamon-pretzels-caramel-dipping.gif)
_Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipes/appetizer/homemade-soft-cinnamon-sugar-pretzel-bites-with-salted-caramel-dipping-sauce.html)_
## Introduction
@@ -18,7 +18,7 @@ It's inspired by `.NET`'s [Unity Container](https://msdn.microsoft.com/library/f
* You start by creating `let dc = DependencyContainer()` and **register all your dependencies, by associating a `protocol` to an `instance` or a `factory`**.
* Then anywhere in your application, you can call `dc.resolve()` to **resolve a `protocol` into an instance of a concrete type** using that `DependencyContainer`.
This allows you to define the real, concrete types only in one place ([typically at the top of your `AppDelegate` for your app](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/AppDelegate.swift#L12-L21), and [in your `setUp` for your Unit Tests](https://github.com/AliSoftware/Dip/blob/master/Example/Tests/SWAPIWebServiceTests.swift#L36-L38)) and then [only work with `protocols` in your code](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/ViewController.swift#L15) (which only define an API contract), without worrying about the real implementation.
This allows you to define the real, concrete types only in one place ([e.g. like this in your app](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/DependencyContainers.swift#L22-L27), and [resetting it in your `setUp` for each Unit Tests](https://github.com/AliSoftware/Dip/blob/master/Example/Tests/SWAPIPersonProviderTests.swift#L17-L21)) and then [only work with `protocols` in your code](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/Providers/SWAPIStarshipProvider.swift#L12) (which only define an API contract), without worrying about the real implementation.
## Advantages of DI and loose coupling
@@ -46,8 +46,7 @@ First, create a `DependencyContainer` and use it to register instances and facto
* `register(factory: _)` will register an instance factory — which generates a new instance each time you `resolve()`.
* You need **cast the instance to the protocol type** you want to register it with (e.g. `register(instance: PlistUsersProvider() as UsersListProviderType)`).
Typically, to register your dependencies as early as possible in your app life-cycle, you will declare a `let dip: DependencyContainer = { … }()` somewhere (for example [at the top of your `AppDelegate.swift`](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/AppDelegate.swift#L12-L21)).
In your (non-hosted, standalone) unit tests, you'll probably [declare them in your `func setUp()`](https://github.com/AliSoftware/Dip/blob/master/Example/Tests/SWAPIWebServiceTests.swift#L36-L38) instead.
Typically, to register your dependencies as early as possible in your app life-cycle, you will declare a `let dip: DependencyContainer = { … }()` somewhere (for example [in a dedicated `.swift` file](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/DependencyContainers.swift#L22-L27)). In your (non-hosted, standalone) unit tests, you'll probably [reset them in your `func setUp()`](https://github.com/AliSoftware/Dip/blob/master/Example/Tests/SWAPIPersonProviderTests.swift#L17-L21) instead.
### Resolve dependencies
@@ -55,20 +54,60 @@ Typically, to register your dependencies as early as possible in your app life-c
* Explicitly specify the return type of `resolve` so that Swift's type inference knows which protocol you're trying to resolve.
* If that protocol was registered as a singleton instance (using `register(instance: …)`, the same instance will be returned each time you call `resolve()` for this protocol type. Otherwise, the instance factory will generate a new instance each time.
### Using block-based initialization
When calling the initializer of `DependencyContainer()`, you can pass a block that will be called right after the initialization. This allows you to have a nice syntax to do all your `register(…)` calls in there, instead of having to do them separately.
It may not seem to provide much, but given the fact that `DependencyContainers` are typically declared as global constants using a top-level `let`, it gets very useful, because instead of having to do it like this:
```swift
let dip: DependencyContainer = {
let dip = DependencyContainer()
dip.register(instance: ProductionEnvironment(analytics: true) as EnvironmentType)
dip.register(instance: WebService() as WebServiceAPI)
return dip
}()
```
You can instead write this exact equivalent code, which is more compact, and indent better in Xcode (as the final closing brack is properly aligned):
```swift
let dip = DependencyContainer { dip in
dip.register(instance: ProductionEnvironment(analytics: true) as EnvironmentType)
dip.register(instance: WebService() as WebServiceAPI)
}
```
### Using tags to associate various factories to one protocol
* If you give a `tag` in the parameter to `register()`, it will associate that instance or factory with this tag, which can be used later during `resolve` (see below).
* `resolve(tag)` will try to find an instance (or instance factory) that match both the requested protocol _and_ the tag. If it doesn't find any, it will fallback to an instance (or instance factory) that only match the requested protocol.
* The tags can be anything, as long as it's of a type conforming to `Equatable`. `DependencyContainer` is a generic class which takes that type as generic parameter (so one `DependencyContainer` will be tied with a given tag type)
* The tags can be StringLiteralType or IntegerLiteralType. That said you can use plain strings or integers as tags.
### Example
```swift
enum WebService: String {
case PersonWS
case StarshipWS
var tag: Tag { return Tag.String(self.rawValue) }
}
let wsDependencies = DependencyContainer<WebService>() { dip in
dip.register(WebService.PersonWS.tag, instance: URLSessionNetworkLayer(baseURL: "http://prod.myapi.com/api/")! as NetworkLayer)
dip.register(WebService.StashipWS.tag, instance: URLSessionNetworkLayer(baseURL: "http://dev.myapi.com/api/")! as NetworkLayer)
}
```
### Concrete Example
Somewhere in your App target, register the dependencies:
```swift
let dip: DependencyContainer<String> = {
let dip = DependencyContainer<String>()
let dip: DependencyContainer = {
let dip = DependencyContainer()
let env = ProductionEnvironment(analytics: true)
dip.register(instance: env as EnvironmentType)
dip.register(instance: WebService() as WebServiceType)
@@ -111,20 +150,23 @@ This way, when running your app target:
But when running your Unit tests target, it will probably resolve to other instances, depending on how you registered your dependencies in your Test Case.
### Complete Example Project
## Work In Progress
You can find a complete example in the `Example/DipSampleApp` project provided in this repository.
* [x] Example project
* [ ] Unit Tests
* [x] README
* [ ] Source Documentation
* [ ] Thread-Safety
This sample project is a bit more complex, but closer to real-world applications (even if this sample is all about StarWars!),
by declaring protocols like `NetworkLayer` which can be resolved to a `URLSessionNetworkLayer` in the real app, but to a dummy
network layer returning fixture data during the Unit Tests.
This sample uses the Star Wars API provided by swapi.co to fetch Star Wars characters and starships info and display them in TableViews.
## Author
## Credits
Olivier Halligon, olivier@halligon.net
This library is authored by **Olivier Halligon**, olivier@halligon.net
## License
**Dip** is available under the **MIT license**. See the `LICENSE` file for more info.
Dip is available under the MIT license. See the LICENSE file for more info.
The animated GIF at the top of this `README.md` is from [this recipe](http://www.kevinandamanda.com/recipes/appetizer/homemade-soft-cinnamon-sugar-pretzel-bites-with-salted-caramel-dipping-sauce.html) on the yummy blog of [Kevin & Amanda](http://www.kevinandamanda.com/recipes/). Go try the recipe!
The image used as the SampleApp LaunchScreen and Icon is from [Matthew Hine](https://commons.wikimedia.org/wiki/File:Chocolate_con_churros_-_San_Ginés,_Madrid.jpg) and is under _CC-by-2.0_.
+175 -64
View File
@@ -8,81 +8,192 @@
import Foundation
// MARK: - DependencyContainer
/**
* Internal representation of a key to associate protocols & tags to an instance factory
*/
private struct ProtoTagKey<TagType : Equatable> : Hashable, Equatable, CustomDebugStringConvertible {
* _Dip_'s Dependency Containers allow you to do very simple **Dependency Injection**
* by associating `protocols` to concrete implementations
*/
public class DependencyContainer {
/**
Use a tag in case you need to register multiple instances or factories
with the same protocol, to differentiate them. Tags can be either String
or Int, to your convenience.
*/
public enum Tag: Equatable {
case String(StringLiteralType)
case Int(IntegerLiteralType)
}
/**
* Internal representation of a key to associate protocols & tags to an instance factory
*/
private struct LookupKey : Hashable, Equatable, CustomDebugStringConvertible {
var protocolType: Any.Type
var associatedTag: TagType?
var associatedTag: Tag?
var hashValue: Int {
return "\(protocolType)-\(associatedTag)".hashValue
return "\(protocolType)-\(associatedTag)".hashValue
}
var debugDescription: String {
return "type: \(protocolType), tag: \(associatedTag)"
return "type: \(protocolType), tag: \(associatedTag)"
}
}
private typealias InstanceType = Any
private typealias InstanceFactory = Tag?->InstanceType
private typealias Key = LookupKey
private var dependencies = [Key : InstanceFactory]()
private var lock: OSSpinLock = OS_SPINLOCK_INIT
// MARK: - Init & Reset
/**
Designated initializer for a DependencyContainer
- parameter configBlock: A configuration block in which you typically put all you `register` calls.
- note: The `configBlock` is simply called at the end of the `init` to let you configure everything.
It is only present for convenience to have a cleaner syntax when declaring and initializing
your `DependencyContainer` instances.
- returns: A new DependencyContainer
*/
public init(@noescape configBlock: (DependencyContainer->Void) = { _ in }) {
configBlock(self)
}
/**
Clear all the previously registered dependencies on this container
*/
public func reset() {
lockAndDo {
dependencies.removeAll()
}
}
// MARK: Register dependencies
/**
Register a `TagType?->T` factory (which takes the tag as parameter) with a given tag
- parameter tag: The arbitrary tag to associate this factory with when registering with that protocol. `nil` to associate with any tag.
- parameter factory: The factory to register, typed/casted as the protocol you want to register it as
- note: You must cast the factory return type to the protocol you want to register it with (e.g `MyClass() as MyAPI`)
*/
public func register<T>(tag: Tag? = nil, factory: Tag?->T) {
let key = Key(protocolType: T.self, associatedTag: tag)
lockAndDo {
dependencies[key] = { factory($0) }
}
}
/**
Register a Void->T factory (which don't care about the tag used)
- parameter tag: The arbitrary tag to associate this factory with when registering with that protocol. `nil` to associate with any tag.
- parameter factory: The factory to register, typed/casted as the protocol you want to register it as
- note: You must cast the factory return type to the protocol you want to register it with (e.g `MyClass() as MyAPI`)
*/
public func register<T>(tag: Tag? = nil, factory: Void->T) {
let key = Key(protocolType: T.self, associatedTag: tag)
lockAndDo {
dependencies[key] = { _ in factory() }
}
}
/**
Register a Singleton instance
- parameter tag: The arbitrary tag to associate this instance with when registering with that protocol. `nil` to associate with any tag.
- parameter instance: The instance to register, typed/casted as the protocol you want to register it as
- note: You must cast the instance to the protocol you want to register it with (e.g `MyClass() as MyAPI`)
*/
public func register<T>(tag: Tag? = nil, @autoclosure(escaping) instance factory: Void->T) {
let key = Key(protocolType: T.self, associatedTag: tag)
lockAndDo {
dependencies[key] = { _ in
let instance = factory()
self.dependencies[key] = { _ in return instance }
return instance
}
}
}
// MARK: Resolve dependencies
/**
Resolve a dependency
- parameter tag: The arbitrary tag to look for when resolving this protocol.
If no instance/factory was registered with this `tag` for this `protocol`,
it will resolve to the instance/factory associated with `nil` (no tag).
*/
public func resolve<T>(tag: Tag? = nil) -> T! {
let key = Key(protocolType: T.self, associatedTag: tag)
let nilKey = Key(protocolType: T.self, associatedTag: nil)
var resolved: T!
lockAndDo { [unowned self] in
guard let factory = self.dependencies[key] ?? self.dependencies[nilKey] else {
fatalError("No instance factory registered with \(key)")
}
resolved = factory(tag) as! T
}
return resolved
}
// MARK: - Private Helper
private func lockAndDo(@noescape block: Void->Void) {
OSSpinLockLock(&lock)
defer { OSSpinLockUnlock(&lock) }
block()
}
}
private func ==<T>(lhs: ProtoTagKey<T>, rhs: ProtoTagKey<T>) -> Bool {
return lhs.protocolType == rhs.protocolType && lhs.associatedTag == rhs.associatedTag
// MARK: - Class Extensions
private func ==(lhs: DependencyContainer.LookupKey, rhs: DependencyContainer.LookupKey) -> Bool {
return lhs.protocolType == rhs.protocolType && lhs.associatedTag == rhs.associatedTag
}
// MARK: - DependencyContainer
public class DependencyContainer<TagType : Equatable> {
typealias InstanceType = Any
typealias InstanceFactory = TagType?->InstanceType
private typealias Key = ProtoTagKey<TagType>
private var dependencies = [Key : InstanceFactory]()
public init() {}
// MARK: Reset all dependencies
public func reset() {
dependencies.removeAll()
}
// MARK: Register dependencies
/// Register a TagType?->T factory (which takes the tag as parameter)
public func register<T : Any>(tag: TagType? = nil, factory: TagType?->T) {
let key = Key(protocolType: T.self, associatedTag: tag)
dependencies[key] = { factory($0) }
}
/// Register a Void->T factory (which don't care about the tag used)
public func register<T : Any>(tag: TagType? = nil, factory: Void->T) {
let key = Key(protocolType: T.self, associatedTag: tag)
dependencies[key] = { _ in factory() }
}
/// Register a Singleton instance
public func register<T : Any>(tag: TagType? = nil, @autoclosure(escaping) instance factory: Void->T) {
let key = Key(protocolType: T.self, associatedTag: tag)
// FIXME: Make it thread-safe
dependencies[key] = { _ in
let instance = factory()
self.dependencies[key] = { _ in return instance }
return instance
}
}
// MARK: Resolve dependencies
/// Resolve a dependency
///
/// **Note** If a tag is given, it will try to resolve using the tag to generate a specific instance,
/// and fallback without the tag if not found with it
public func resolve<T>(tag: TagType? = nil) -> T! {
let key = Key(protocolType: T.self, associatedTag: tag)
let nilKey = Key(protocolType: T.self, associatedTag: nil)
guard let factory = dependencies[key] ?? dependencies[nilKey] else {
fatalError("No instance factory registered with \(key)")
}
return factory(tag) as! T
}
extension DependencyContainer.Tag: IntegerLiteralConvertible {
public init(integerLiteral value: IntegerLiteralType) {
self = .Int(value)
}
}
extension DependencyContainer.Tag: StringLiteralConvertible {
public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType
public typealias UnicodeScalarLiteralType = StringLiteralType
public init(stringLiteral value: StringLiteralType) {
self = .String(value)
}
public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
self.init(stringLiteral: value)
}
public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
self.init(stringLiteral: value)
}
}
public func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
switch (lhs, rhs) {
case let (.String(lhsString), .String(rhsString)):
return lhsString == rhsString
case let (.Int(lhsInt), .Int(rhsInt)):
return lhsInt == rhsInt
default:
return false
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB