Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6085ce5f21 | |||
| 3bca744c82 | |||
| c311eea591 | |||
| 120a98b157 | |||
| 937709fba2 |
@@ -13,6 +13,7 @@ build/
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
|
||||
@@ -7,63 +7,55 @@
|
||||
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 */; };
|
||||
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 = (); }; };
|
||||
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, ); }; };
|
||||
/* 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>"; };
|
||||
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; };
|
||||
@@ -98,60 +90,86 @@
|
||||
/* 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 */,
|
||||
090012371BC6FEEA0079C600 /* APIs */,
|
||||
090012381BC6FEFD0079C600 /* PersonProviders */,
|
||||
090012391BC6FF080079C600 /* StarshipProviders */,
|
||||
);
|
||||
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 */,
|
||||
);
|
||||
name = APIs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
090012381BC6FEFD0079C600 /* PersonProviders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0900121C1BC6FECA0079C600 /* DummyPilotProvider.swift */,
|
||||
0900121E1BC6FECA0079C600 /* PlistPersonProvider.swift */,
|
||||
);
|
||||
name = PersonProviders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
090012391BC6FF080079C600 /* StarshipProviders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
090012431BC708A00079C600 /* DummyStarshipProvider.swift */,
|
||||
0900121D1BC6FECA0079C600 /* HardCodedStarshipProvider.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 */,
|
||||
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>";
|
||||
@@ -310,9 +328,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 +442,22 @@
|
||||
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 */,
|
||||
09D795FF1BC71F5A003C68EB /* PersonListViewController.swift in Sources */,
|
||||
0900122A1BC6FECA0079C600 /* PersonCell.swift in Sources */,
|
||||
09D796011BC722C0003C68EB /* StarshipListViewController.swift in Sources */,
|
||||
0900122C1BC6FECA0079C600 /* PersonProviderAPI.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 */,
|
||||
090012421BC7059E0079C600 /* Starship.swift in Sources */,
|
||||
0900123D1BC7012A0079C600 /* StarshipProviderAPI.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 */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -446,32 +466,12 @@
|
||||
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 */,
|
||||
);
|
||||
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 = (
|
||||
|
||||
@@ -9,14 +9,19 @@
|
||||
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)
|
||||
let dip: DependencyContainer<Int> = {
|
||||
let dip = DependencyContainer<Int>()
|
||||
|
||||
// 1) Register the PersonProviderAPI singleton, one generic and one specific for a specific personID
|
||||
dip.register(instance: DummyPilotProvider() as PersonProviderAPI)
|
||||
let mainPersonProvider = PlistPersonProvider(plist: "mainPilot")
|
||||
dip.register(0, instance: mainPersonProvider as PersonProviderAPI)
|
||||
|
||||
// 2) Register the StarshipProviderAPI factories, one generic and one specific for a specific starshipID
|
||||
dip.register() { HardCodedStarshipProvider() as StarshipProviderAPI }
|
||||
let pilotName = mainPersonProvider.people[0].name
|
||||
dip.register(0) { DummyStarshipProvider(pilotName: pilotName) as StarshipProviderAPI }
|
||||
|
||||
return dip
|
||||
}()
|
||||
|
||||
@@ -29,6 +34,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.fetchAllObjects()
|
||||
}
|
||||
if let starshipListVC = vcs[1].topViewController as? StarshipListViewController {
|
||||
starshipListVC.fetchAllObjects()
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
],
|
||||
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
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"
|
||||
}
|
||||
}
|
||||
|
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 & Height"/>
|
||||
<segment title="Hair & 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>
|
||||
@@ -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,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="470" 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="473" 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="338" 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="341" 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="522" y="32" width="25" height="20.5"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="25" 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="522" y="60" width="25" 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>
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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]),
|
||||
]
|
||||
|
||||
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,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,57 @@
|
||||
//
|
||||
// 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,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)
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,49 @@
|
||||
//
|
||||
// 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 }
|
||||
|
||||
var fetchIDs: ([Int] -> Void) -> Void { get }
|
||||
var fetchOne: (Int, ObjectType? -> Void) -> Void { get }
|
||||
}
|
||||
|
||||
extension FetchableTrait {
|
||||
func fetchObjects(objectIDs: [Int]) {
|
||||
self.batchRequestID += 1
|
||||
let batch = self.batchRequestID
|
||||
|
||||
objects?.removeAll()
|
||||
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.tableView?.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchAllObjects() {
|
||||
self.batchRequestID += 1
|
||||
let batch = self.batchRequestID
|
||||
|
||||
fetchIDs() { objectIDs in
|
||||
guard batch == self.batchRequestID else { return }
|
||||
self.fetchObjects(objectIDs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
lazy var fetchIDs: ([Int] -> Void) -> Void = (dip.resolve() as PersonProviderAPI).fetchIDs
|
||||
lazy var fetchOne: (Int, Person? -> Void) -> Void = { personID, completion in
|
||||
let provider = dip.resolve(personID) as PersonProviderAPI
|
||||
return provider.fetch(personID, completion: completion)
|
||||
}
|
||||
|
||||
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.fetchObjects(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,48 @@
|
||||
//
|
||||
// StarshipListViewController.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 09/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class StarshipListViewController : UITableViewController, FetchableTrait {
|
||||
var objects: [Starship]?
|
||||
var batchRequestID = 0
|
||||
|
||||
var provider: (Int? -> StarshipProviderAPI) = { dip.resolve($0) }
|
||||
|
||||
lazy var fetchIDs: ([Int] -> Void) -> Void = self.provider(nil).fetchIDs
|
||||
lazy var fetchOne: (Int, Starship? -> Void) -> Void = { shipID, completion in
|
||||
self.provider(shipID).fetch(shipID, completion: completion)
|
||||
}
|
||||
|
||||
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.fetchObjects(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
|
||||
}
|
||||
}
|
||||
@@ -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,87 +3,87 @@ import XCTest
|
||||
import Dip
|
||||
|
||||
|
||||
var dip = DependencyContainer<PersonFormatterTag>()
|
||||
var dip = DependencyContainer<String>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
//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)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[](http://cocoapods.org/pods/Dip)
|
||||
|
||||

|
||||
_Photo by [Matthew Hine](http://www.flickr.com/photos/75771631@N00), cc-by-2.0_
|
||||
_Photo by [Matthew Hine](https://commons.wikimedia.org/wiki/File:Chocolate_con_churros_-_San_Ginés,_Madrid.jpg), cc-by-2.0_
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||