storyboardlint 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +18 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +10 -0
  7. data/README.md +1 -0
  8. data/Rakefile +7 -1
  9. data/VERSION +1 -1
  10. data/lib/storyboardlint.rb +96 -52
  11. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/Base.lproj/Main_iPad.storyboard +138 -0
  12. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/Base.lproj/Main_iPhone.storyboard +125 -0
  13. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  14. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/Images.xcassets/LaunchImage.launchimage/Contents.json +51 -0
  15. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/SPWKAppDelegate.h +15 -0
  16. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/SPWKAppDelegate.m +51 -0
  17. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/SPWKDetailViewController.h +16 -0
  18. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/SPWKDetailViewController.m +80 -0
  19. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/SPWKMasterViewController.h +17 -0
  20. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/SPWKMasterViewController.m +131 -0
  21. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/StoryboardLintTest-Info.plist +59 -0
  22. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/StoryboardLintTest-Prefix.pch +16 -0
  23. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/TestView.xib +25 -0
  24. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/en.lproj/InfoPlist.strings +2 -0
  25. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest/main.m +18 -0
  26. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest.xcodeproj/project.pbxproj +466 -0
  27. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  28. data/spec/fixtures/StoryboardLintTest/StoryboardLintTest.xcodeproj/project.xcworkspace/xcshareddata/StoryboardLintTest.xccheckout +41 -0
  29. data/spec/linter_spec.rb +26 -0
  30. data/spec/matcher_spec.rb +156 -0
  31. data/spec/source_scanner_spec.rb +139 -0
  32. data/spec/spec_helper.rb +19 -0
  33. data/spec/storyboard_scanner_spec.rb +56 -0
  34. data/storyboardlint.gemspec +31 -2
  35. metadata +42 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58d343d4d968254f21f6a1e31d508c073a779fc4
4
- data.tar.gz: a8675e78e75b2d299bbf8e19caa9ce95cf3bf9d9
3
+ metadata.gz: cff590128484b450950874dc541b476c2dfdc69e
4
+ data.tar.gz: a27efee054708381b70b433c31ebb7ef5b68bd7e
5
5
  SHA512:
6
- metadata.gz: 94615f5aa57c7b7152be2f1a406b6a37b486fdff520d1bdf8e1da17ab31d0e91f8fe436b18f834853859acbf108f355b634c672ec6d1b109d08e6f90d50bdf67
7
- data.tar.gz: 80a5e312da89a90b28c69e4391c0eab9fecb4b5aa0f4288f6bc03738aaac09c6fe1e6f44ea37a1984080d13ea45740fb6ea841ff0c7dd23b793a5d3aa68c62bf
6
+ metadata.gz: e9d1b1fc5c6716ad240c41ba662617146cbe1d1efa661125e2dfbfb131a126240d7e13584e1a6f5151358ded9f0a288a273dfb62e56e159dd2f6ae7acdbb4e7c
7
+ data.tar.gz: 9ca7b267a26383ca59d050716737227de9a567ae3e651137d83bf4f70622079dbd7c205ff9c10dc1467e86830db7fae2dcefdb1a8da518c3258d5f21ef002c24
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - XIB files are now also scanned for reuse identifiers
6
+ - Added tests
7
+
8
+ ## 0.1.2
9
+
10
+ - UTF-8 support
11
+
12
+ ## 0.1.1
13
+
14
+ - Support for custom pre- and suffixes for Storyboard IDs, Segue IDs and reuse IDs
15
+
16
+ ## 0.1.0
17
+
18
+ - First release
data/Gemfile CHANGED
@@ -8,4 +8,6 @@ gem "nokogiri", "~> 1.5.0"
8
8
  group :development do
9
9
  gem "bundler", "~> 1.3.5"
10
10
  gem "jeweler", "~> 1.8.0"
11
+ gem "rspec", "~> 2.14.0"
12
+
11
13
  end
data/Gemfile.lock CHANGED
@@ -3,6 +3,7 @@ GEM
3
3
  specs:
4
4
  addressable (2.3.5)
5
5
  builder (3.2.2)
6
+ diff-lcs (1.2.5)
6
7
  faraday (0.8.9)
7
8
  multipart-post (~> 1.2.0)
8
9
  git (1.2.6)
@@ -41,6 +42,14 @@ GEM
41
42
  rake (10.1.1)
42
43
  rdoc (4.1.1)
43
44
  json (~> 1.4)
45
+ rspec (2.14.1)
46
+ rspec-core (~> 2.14.0)
47
+ rspec-expectations (~> 2.14.0)
48
+ rspec-mocks (~> 2.14.0)
49
+ rspec-core (2.14.7)
50
+ rspec-expectations (2.14.5)
51
+ diff-lcs (>= 1.1.3, < 2.0)
52
+ rspec-mocks (2.14.6)
44
53
 
45
54
  PLATFORMS
46
55
  ruby
@@ -49,3 +58,4 @@ DEPENDENCIES
49
58
  bundler (~> 1.3.5)
50
59
  jeweler (~> 1.8.0)
51
60
  nokogiri (~> 1.5.0)
61
+ rspec (~> 2.14.0)
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  StoryboardLint
2
2
  ==============
3
+ [![Build Status](https://travis-ci.org/jfahrenkrug/StoryboardLint.png?branch=master)](https://travis-ci.org/jfahrenkrug/StoryboardLint)
3
4
 
4
5
  A lint tool for UIStoryboard to find wrong classes and wrong storyboard/segue/reuse identifiers.
5
6
 
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
+ require "rspec/core/rake_task"
3
4
  begin
4
5
  Bundler.setup(:default, :development)
5
6
  rescue Bundler::BundlerError => e
@@ -22,4 +23,9 @@ Jeweler::Tasks.new do |gem|
22
23
 
23
24
  # dependencies defined in Gemfile
24
25
  end
25
- Jeweler::RubygemsDotOrgTasks.new
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ RSpec::Core::RakeTask.new
29
+
30
+ task :test => :spec
31
+ task :default => :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -9,6 +9,10 @@ require 'optparse'
9
9
  module StoryboardLint
10
10
  class StoryboardScanner
11
11
  def initialize(src_root)
12
+ if !File.directory?(src_root)
13
+ raise ArgumentError, "The directory '#{src_root}' does not exist."
14
+ end
15
+
12
16
  @src_root = src_root
13
17
  @scan_performed = false
14
18
  end
@@ -20,6 +24,35 @@ module StoryboardLint
20
24
  @sb_files = Dir.glob(File.join(@src_root, "**/*.storyboard"))
21
25
  end
22
26
 
27
+ def xib_files
28
+ return @xib_files if @xib_files
29
+
30
+ # find all XIB files...
31
+ @xib_files = Dir.glob(File.join(@src_root, "**/*.xib"))
32
+ end
33
+
34
+ def segue_ids
35
+ scan_files
36
+ @segue_ids
37
+ end
38
+
39
+ def storyboard_ids
40
+ scan_files
41
+ @storyboard_ids
42
+ end
43
+
44
+ def reuse_ids
45
+ scan_files
46
+ @reuse_ids
47
+ end
48
+
49
+ def custom_class_names
50
+ scan_files
51
+ @custom_class_names
52
+ end
53
+
54
+ private
55
+
23
56
  def scan_files
24
57
  if !@scan_performed
25
58
  @segue_ids ||= []
@@ -40,9 +73,39 @@ module StoryboardLint
40
73
  @custom_class_names += doc.xpath("//@customClass").to_a.map {|match| {:file => sb_file, :class_name => match.to_s}}
41
74
  end
42
75
 
76
+ xib_files.each do |xib_file|
77
+ xib_source = File.open(xib_file)
78
+ doc = Nokogiri::XML(xib_source)
79
+
80
+ @reuse_ids += doc.xpath("//@reuseIdentifier").to_a.map {|match| {:file => xib_file, :id => match.to_s}}
81
+ end
82
+
43
83
  @scan_performed = true
44
84
  end
45
85
  end
86
+ end
87
+
88
+ class SourceScanner
89
+ def initialize(src_root, matcher)
90
+ if !File.directory?(src_root)
91
+ raise ArgumentError, "The directory '#{src_root}' does not exist."
92
+ end
93
+
94
+ if !matcher
95
+ raise ArgumentError, "The matcher cannot be nil."
96
+ end
97
+
98
+ @matcher = matcher
99
+ @src_root = src_root
100
+ @scan_performed = false
101
+ end
102
+
103
+ def source_files
104
+ return @source_files if @source_files
105
+
106
+ # find all *.h, *.c, *.m and *.mm files
107
+ @source_files = Dir.glob(File.join(@src_root, "**/*.{h,c,m,mm}"))
108
+ end
46
109
 
47
110
  def segue_ids
48
111
  scan_files
@@ -59,25 +122,12 @@ module StoryboardLint
59
122
  @reuse_ids
60
123
  end
61
124
 
62
- def custom_class_names
125
+ def class_names
63
126
  scan_files
64
- @custom_class_names
65
- end
66
- end
67
-
68
- class SourceScanner
69
- def initialize(src_root, matcher)
70
- @matcher = matcher
71
- @src_root = src_root
72
- @scan_performed = false
127
+ @class_names
73
128
  end
74
129
 
75
- def source_files
76
- return @source_files if @source_files
77
-
78
- # find all *.h, *.c, *.m and *.mm files
79
- @source_files = Dir.glob(File.join(@src_root, "**/*.{h,c,m,mm}"))
80
- end
130
+ private
81
131
 
82
132
  def scan_files
83
133
  if !@scan_performed
@@ -113,26 +163,6 @@ module StoryboardLint
113
163
  @scan_performed = true
114
164
  end
115
165
  end
116
-
117
- def class_names
118
- scan_files
119
- @class_names
120
- end
121
-
122
- def segue_ids
123
- scan_files
124
- @segue_ids
125
- end
126
-
127
- def storyboard_ids
128
- scan_files
129
- @storyboard_ids
130
- end
131
-
132
- def reuse_ids
133
- scan_files
134
- @reuse_ids
135
- end
136
166
  end
137
167
 
138
168
  class Matcher
@@ -152,6 +182,19 @@ module StoryboardLint
152
182
  @reuse_id_regex_source = create_source_regex(DEFAULT_REUSE_ID_PREFIX, options.reuse_prefix, options.reuse_suffix)
153
183
  @reuse_id_regex_sb = create_storyboard_regex(DEFAULT_REUSE_ID_PREFIX, options.reuse_prefix, options.reuse_suffix)
154
184
  end
185
+
186
+ def class_regex
187
+ /@interface\s+([a-zA-Z_]+\w*)/
188
+ end
189
+
190
+ [:storyboard, :segue, :reuse].each do |name|
191
+ [:sb, :source].each do |kind|
192
+ method_name = "#{name}_id_regex_#{kind}"
193
+ define_method(method_name) { instance_variable_get("@#{method_name}") }
194
+ end
195
+ end
196
+
197
+ private
155
198
 
156
199
  def create_source_regex(default_prefix, prefix, suffix)
157
200
  inner_regex_part = %{(?:\\"|[^"])+}
@@ -180,21 +223,22 @@ module StoryboardLint
180
223
 
181
224
  sb
182
225
  end
183
-
184
- def class_regex
185
- /@interface\s+([a-zA-Z_]+\w*)/
186
- end
187
-
188
- [:storyboard, :segue, :reuse].each do |name|
189
- [:sb, :source].each do |kind|
190
- method_name = "#{name}_id_regex_#{kind}"
191
- define_method(method_name) { instance_variable_get("@#{method_name}") }
192
- end
193
- end
194
226
  end
195
227
 
196
228
  class Linter
197
229
  def initialize(sb_scanner, source_scanner, matcher)
230
+ if !sb_scanner
231
+ raise ArgumentError, "The sb_scanner cannot be nil."
232
+ end
233
+
234
+ if !source_scanner
235
+ raise ArgumentError, "The source_scanner cannot be nil."
236
+ end
237
+
238
+ if !matcher
239
+ raise ArgumentError, "The matcher cannot be nil."
240
+ end
241
+
198
242
  @matcher = matcher
199
243
  @sb_scanner = sb_scanner
200
244
  @source_scanner = source_scanner
@@ -227,12 +271,12 @@ module StoryboardLint
227
271
  end
228
272
 
229
273
  def check_ids
230
- [{:method_name => :segue_ids, :name => 'Segue ID'},
231
- {:method_name => :storyboard_ids, :name => 'Storyboard ID'},
232
- {:method_name => :reuse_ids, :name => 'Reuse ID'}].each do |data|
274
+ [{:method_name => :segue_ids, :name => 'Segue ID', :target => 'Storyboard'},
275
+ {:method_name => :storyboard_ids, :name => 'Storyboard ID', :target => 'Storyboard'},
276
+ {:method_name => :reuse_ids, :name => 'Reuse ID', :target => 'Storyboard or XIB'}].each do |data|
233
277
  @source_scanner.send(data[:method_name]).each do |source_item|
234
278
  if !@sb_scanner.send(data[:method_name]).map {|sb_item| sb_item[:id]}.include?(source_item[:id])
235
- puts "#{source_item[:file]}:#{source_item[:line]}: warning: #{data[:name]} '#{source_item[:id]}' could not be found in any Storyboard."
279
+ puts "#{source_item[:file]}:#{source_item[:line]}: warning: #{data[:name]} '#{source_item[:id]}' could not be found in any #{data[:target]}."
236
280
  end
237
281
  end
238
282
  end
@@ -279,7 +323,7 @@ module StoryboardLint
279
323
 
280
324
  # Another typical switch to print the version.
281
325
  opts.on_tail("--version", "Show version") do
282
- puts "StoryboardLint v0.1.2"
326
+ puts "StoryboardLint v0.2.0"
283
327
  exit
284
328
  end
285
329
  end
@@ -0,0 +1,138 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="4514" systemVersion="13A598" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" initialViewController="H1p-Uh-vWS">
3
+ <dependencies>
4
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
5
+ </dependencies>
6
+ <scenes>
7
+ <!--Navigation Controller-->
8
+ <scene sceneID="pY4-Hu-kfo">
9
+ <objects>
10
+ <navigationController id="RMx-3f-FxP" sceneMemberID="viewController">
11
+ <navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="Pmd-2v-anx">
12
+ <autoresizingMask key="autoresizingMask"/>
13
+ </navigationBar>
14
+ <connections>
15
+ <segue destination="7bK-jq-Zjz" kind="relationship" relationship="rootViewController" id="tsl-Nk-0bq"/>
16
+ </connections>
17
+ </navigationController>
18
+ <placeholder placeholderIdentifier="IBFirstResponder" id="8fS-aE-onr" sceneMemberID="firstResponder"/>
19
+ </objects>
20
+ <point key="canvasLocation" x="448" y="-630"/>
21
+ </scene>
22
+ <!--Detail View Controller - Detail-->
23
+ <scene sceneID="yUG-lL-AsK">
24
+ <objects>
25
+ <viewController title="Detail" id="JEX-9P-axG" customClass="SPWKDetailViewController" sceneMemberID="viewController">
26
+ <layoutGuides>
27
+ <viewControllerLayoutGuide type="top" id="E9l-JE-Xxa"/>
28
+ <viewControllerLayoutGuide type="bottom" id="NXR-7p-zaA"/>
29
+ </layoutGuides>
30
+ <view key="view" contentMode="scaleToFill" id="svH-Pt-448">
31
+ <rect key="frame" x="0.0" y="0.0" width="703" height="768"/>
32
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
33
+ <subviews>
34
+ <label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Detail view content goes here" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="0XM-y9-sOw">
35
+ <rect key="frame" x="20" y="376" width="663" height="17"/>
36
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
37
+ <fontDescription key="fontDescription" type="system" size="system"/>
38
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
39
+ <nil key="highlightedColor"/>
40
+ </label>
41
+ </subviews>
42
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
43
+ <constraints>
44
+ <constraint firstItem="0XM-y9-sOw" firstAttribute="leading" secondItem="svH-Pt-448" secondAttribute="leading" constant="20" symbolic="YES" id="Tsc-yG-G1q"/>
45
+ <constraint firstItem="0XM-y9-sOw" firstAttribute="centerY" secondItem="svH-Pt-448" secondAttribute="centerY" id="jWN-iV-94e"/>
46
+ <constraint firstAttribute="trailing" secondItem="0XM-y9-sOw" secondAttribute="trailing" constant="20" symbolic="YES" id="tHV-ZD-HQj"/>
47
+ </constraints>
48
+ <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
49
+ </view>
50
+ <toolbarItems/>
51
+ <navigationItem key="navigationItem" title="Detail" id="mOI-FS-AaM"/>
52
+ <connections>
53
+ <outlet property="detailDescriptionLabel" destination="0XM-y9-sOw" id="deQ-Na-JPF"/>
54
+ </connections>
55
+ </viewController>
56
+ <placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
57
+ </objects>
58
+ <point key="canvasLocation" x="448" y="248"/>
59
+ </scene>
60
+ <!--Split View Controller-->
61
+ <scene sceneID="Nki-YV-4Qg">
62
+ <objects>
63
+ <splitViewController id="H1p-Uh-vWS" sceneMemberID="viewController">
64
+ <toolbarItems/>
65
+ <simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="blackOpaque"/>
66
+ <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
67
+ <connections>
68
+ <segue destination="RMx-3f-FxP" kind="relationship" relationship="masterViewController" id="BlO-5A-QYV"/>
69
+ <segue destination="vC3-pB-5Vb" kind="relationship" relationship="detailViewController" id="Tll-UG-LXB"/>
70
+ </connections>
71
+ </splitViewController>
72
+ <placeholder placeholderIdentifier="IBFirstResponder" id="cZU-Oi-B1e" sceneMemberID="firstResponder"/>
73
+ </objects>
74
+ <point key="canvasLocation" x="-687" y="-630"/>
75
+ </scene>
76
+ <!--Master View Controller - Master-->
77
+ <scene sceneID="smW-Zh-WAh">
78
+ <objects>
79
+ <tableViewController title="Master" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="SPWKMasterViewController" sceneMemberID="viewController">
80
+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="r7i-6Z-zg0">
81
+ <rect key="frame" x="0.0" y="0.0" width="320" height="768"/>
82
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
83
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
84
+ <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
85
+ <prototypes>
86
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="Cell" textLabel="Arm-wq-HPj" style="IBUITableViewCellStyleDefault" id="WCw-Qf-5nD">
87
+ <rect key="frame" x="0.0" y="86" width="320" height="44"/>
88
+ <autoresizingMask key="autoresizingMask"/>
89
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WCw-Qf-5nD" id="j8x-TT-mEF">
90
+ <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
91
+ <autoresizingMask key="autoresizingMask"/>
92
+ <subviews>
93
+ <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Arm-wq-HPj">
94
+ <rect key="frame" x="15" y="0.0" width="290" height="43"/>
95
+ <autoresizingMask key="autoresizingMask"/>
96
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
97
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
98
+ <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
99
+ </label>
100
+ </subviews>
101
+ </tableViewCellContentView>
102
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
103
+ </tableViewCell>
104
+ </prototypes>
105
+ <sections/>
106
+ <connections>
107
+ <outlet property="dataSource" destination="7bK-jq-Zjz" id="Gho-Na-rnu"/>
108
+ <outlet property="delegate" destination="7bK-jq-Zjz" id="RA6-mI-bju"/>
109
+ </connections>
110
+ </tableView>
111
+ <navigationItem key="navigationItem" title="Master" id="Zdf-7t-Un8"/>
112
+ </tableViewController>
113
+ <placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
114
+ </objects>
115
+ <point key="canvasLocation" x="859" y="-631"/>
116
+ </scene>
117
+ <!--Navigation Controller-->
118
+ <scene sceneID="r7l-gg-dq7">
119
+ <objects>
120
+ <navigationController id="vC3-pB-5Vb" sceneMemberID="viewController">
121
+ <navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="DjV-YW-jjY">
122
+ <autoresizingMask key="autoresizingMask"/>
123
+ </navigationBar>
124
+ <connections>
125
+ <segue destination="JEX-9P-axG" kind="relationship" relationship="rootViewController" id="GKi-kA-LjT"/>
126
+ </connections>
127
+ </navigationController>
128
+ <placeholder placeholderIdentifier="IBFirstResponder" id="SLD-UC-DBI" userLabel="First Responder" sceneMemberID="firstResponder"/>
129
+ </objects>
130
+ <point key="canvasLocation" x="-366" y="248"/>
131
+ </scene>
132
+ </scenes>
133
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
134
+ <simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackOpaque"/>
135
+ <simulatedOrientationMetrics key="orientation"/>
136
+ <simulatedScreenMetrics key="destination"/>
137
+ </simulatedMetricsContainer>
138
+ </document>
@@ -0,0 +1,125 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="4514" systemVersion="13A598" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="rS3-R9-Ivy">
3
+ <dependencies>
4
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
5
+ </dependencies>
6
+ <scenes>
7
+ <!--Nonexistent View Controller-->
8
+ <scene sceneID="sqY-Eh-LZl">
9
+ <objects>
10
+ <viewController id="ggl-FL-rMO" customClass="NonexistentViewController" sceneMemberID="viewController">
11
+ <layoutGuides>
12
+ <viewControllerLayoutGuide type="top" id="DHG-f8-iSv"/>
13
+ <viewControllerLayoutGuide type="bottom" id="Pcc-sg-8SB"/>
14
+ </layoutGuides>
15
+ <view key="view" contentMode="scaleToFill" id="P5D-RH-Ckg">
16
+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
17
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
18
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
19
+ </view>
20
+ </viewController>
21
+ <placeholder placeholderIdentifier="IBFirstResponder" id="mRF-bn-7H8" userLabel="First Responder" sceneMemberID="firstResponder"/>
22
+ </objects>
23
+ <point key="canvasLocation" x="-224" y="-244"/>
24
+ </scene>
25
+ <!--Navigation Controller-->
26
+ <scene sceneID="cUi-kZ-frf">
27
+ <objects>
28
+ <navigationController storyboardIdentifier="sb_navigationControllerStoryboard" id="rS3-R9-Ivy" sceneMemberID="viewController">
29
+ <navigationBar key="navigationBar" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="yXu-0R-QUA">
30
+ <autoresizingMask key="autoresizingMask"/>
31
+ </navigationBar>
32
+ <connections>
33
+ <segue destination="pGg-6v-bdr" kind="relationship" relationship="rootViewController" id="RxB-wf-QIq"/>
34
+ </connections>
35
+ </navigationController>
36
+ <placeholder placeholderIdentifier="IBFirstResponder" id="eq9-QA-ai8" sceneMemberID="firstResponder"/>
37
+ </objects>
38
+ <point key="canvasLocation" x="-1" y="64"/>
39
+ </scene>
40
+ <!--Master View Controller - Master-->
41
+ <scene sceneID="VgW-fR-Quf">
42
+ <objects>
43
+ <tableViewController storyboardIdentifier="sb_masterControllerStoryboard" title="Master" id="pGg-6v-bdr" customClass="SPWKMasterViewController" sceneMemberID="viewController">
44
+ <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="mLL-gJ-YKr">
45
+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
46
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
47
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
48
+ <prototypes>
49
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ruid_TableCell" textLabel="2pz-XF-uhl" style="IBUITableViewCellStyleDefault" id="m0d-ak-lc9">
50
+ <rect key="frame" x="0.0" y="86" width="320" height="44"/>
51
+ <autoresizingMask key="autoresizingMask"/>
52
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="m0d-ak-lc9" id="1Yu-d4-OdB">
53
+ <rect key="frame" x="0.0" y="0.0" width="287" height="43"/>
54
+ <autoresizingMask key="autoresizingMask"/>
55
+ <subviews>
56
+ <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2pz-XF-uhl">
57
+ <rect key="frame" x="15" y="0.0" width="270" height="43"/>
58
+ <autoresizingMask key="autoresizingMask"/>
59
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
60
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
61
+ <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
62
+ </label>
63
+ </subviews>
64
+ </tableViewCellContentView>
65
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
66
+ <connections>
67
+ <segue destination="Ah7-4n-0Wa" kind="push" identifier="seg_showDetailSegue" id="jUr-3t-vfg"/>
68
+ </connections>
69
+ </tableViewCell>
70
+ </prototypes>
71
+ <sections/>
72
+ <connections>
73
+ <outlet property="dataSource" destination="pGg-6v-bdr" id="P41-gY-KXY"/>
74
+ <outlet property="delegate" destination="pGg-6v-bdr" id="Y6K-Cp-Qkv"/>
75
+ </connections>
76
+ </tableView>
77
+ <navigationItem key="navigationItem" title="Master" id="tQt-TN-PWz"/>
78
+ </tableViewController>
79
+ <placeholder placeholderIdentifier="IBFirstResponder" id="6Cn-md-YlS" sceneMemberID="firstResponder"/>
80
+ </objects>
81
+ <point key="canvasLocation" x="459" y="64"/>
82
+ </scene>
83
+ <!--Detail View Controller - Detail-->
84
+ <scene sceneID="Cn3-H9-jdl">
85
+ <objects>
86
+ <viewController storyboardIdentifier="sb_detailControllerStoryboard" title="Detail" id="Ah7-4n-0Wa" customClass="SPWKDetailViewController" sceneMemberID="viewController">
87
+ <layoutGuides>
88
+ <viewControllerLayoutGuide type="top" id="gPs-rF-5IM"/>
89
+ <viewControllerLayoutGuide type="bottom" id="cfK-9t-i1J"/>
90
+ </layoutGuides>
91
+ <view key="view" contentMode="scaleToFill" id="MMQ-IT-qOo">
92
+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
93
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
94
+ <subviews>
95
+ <label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Detail view content goes here" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="Lei-5M-9Gs">
96
+ <rect key="frame" x="20" y="276" width="280" height="17"/>
97
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
98
+ <fontDescription key="fontDescription" type="system" size="system"/>
99
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
100
+ <nil key="highlightedColor"/>
101
+ </label>
102
+ </subviews>
103
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
104
+ <constraints>
105
+ <constraint firstItem="Lei-5M-9Gs" firstAttribute="leading" secondItem="MMQ-IT-qOo" secondAttribute="leading" constant="20" symbolic="YES" id="62x-JV-TTJ"/>
106
+ <constraint firstItem="Lei-5M-9Gs" firstAttribute="centerY" secondItem="MMQ-IT-qOo" secondAttribute="centerY" id="JzS-HC-Rnl"/>
107
+ <constraint firstAttribute="trailing" secondItem="Lei-5M-9Gs" secondAttribute="trailing" constant="20" symbolic="YES" id="pXB-RP-Zz6"/>
108
+ </constraints>
109
+ </view>
110
+ <navigationItem key="navigationItem" title="Detail" id="cra-N8-TIN"/>
111
+ <connections>
112
+ <outlet property="detailDescriptionLabel" destination="Lei-5M-9Gs" id="sCT-F7-F6f"/>
113
+ </connections>
114
+ </viewController>
115
+ <placeholder placeholderIdentifier="IBFirstResponder" id="lrm-kH-fPn" sceneMemberID="firstResponder"/>
116
+ </objects>
117
+ <point key="canvasLocation" x="902" y="64"/>
118
+ </scene>
119
+ </scenes>
120
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
121
+ <simulatedStatusBarMetrics key="statusBar"/>
122
+ <simulatedOrientationMetrics key="orientation"/>
123
+ <simulatedScreenMetrics key="destination" type="retina4"/>
124
+ </simulatedMetricsContainer>
125
+ </document>
@@ -0,0 +1,53 @@
1
+ {
2
+ "images" : [
3
+ {
4
+ "idiom" : "iphone",
5
+ "size" : "29x29",
6
+ "scale" : "2x"
7
+ },
8
+ {
9
+ "idiom" : "iphone",
10
+ "size" : "40x40",
11
+ "scale" : "2x"
12
+ },
13
+ {
14
+ "idiom" : "iphone",
15
+ "size" : "60x60",
16
+ "scale" : "2x"
17
+ },
18
+ {
19
+ "idiom" : "ipad",
20
+ "size" : "29x29",
21
+ "scale" : "1x"
22
+ },
23
+ {
24
+ "idiom" : "ipad",
25
+ "size" : "29x29",
26
+ "scale" : "2x"
27
+ },
28
+ {
29
+ "idiom" : "ipad",
30
+ "size" : "40x40",
31
+ "scale" : "1x"
32
+ },
33
+ {
34
+ "idiom" : "ipad",
35
+ "size" : "40x40",
36
+ "scale" : "2x"
37
+ },
38
+ {
39
+ "idiom" : "ipad",
40
+ "size" : "76x76",
41
+ "scale" : "1x"
42
+ },
43
+ {
44
+ "idiom" : "ipad",
45
+ "size" : "76x76",
46
+ "scale" : "2x"
47
+ }
48
+ ],
49
+ "info" : {
50
+ "version" : 1,
51
+ "author" : "xcode"
52
+ }
53
+ }