├── fastlane
├── .env
├── Scanfile
├── .env.default
├── .env.gitsubmodules
├── .env.cocoapod
├── .env.deploy
├── README.md
└── Fastfile
├── Cocoapod
├── Podfile
├── StoryboardKit.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── CocoapodTests.xcscheme
│ └── project.pbxproj
├── StoryboardKit.xcworkspace
│ └── contents.xcworkspacedata
└── Podfile.lock
├── Gemfile
├── .gitmodules
├── StoryboardKitTests
├── Images.xcassets
│ └── Zzzzzz.imageset
│ │ ├── Zzzzzz.png
│ │ └── Contents.json
├── Info.plist
├── StoryboardInfoTests.swift
├── ClassInfoTests.swift
├── StoryboardFileParserTests.swift
├── TableViewInstanceInfoTests.swift
├── ApplicationInfoTests.swift
├── StoryboardInstanceInfoTests.swift
├── ViewInstanceInfoTests.swift
└── StoryboardKit.storyboard
├── StoryboardKit.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── StoryboardKit.xcscmblueprint
└── xcshareddata
│ └── xcschemes
│ └── StoryboardKit.xcscheme
├── Tools
├── generateDocs.sh
└── matchVersiontoBranch.sh
├── .gitignore
├── StoryboardKit
├── StoryboardKit.h
├── Views
│ ├── TableViewClassInfo.swift
│ ├── CollectionViewClassInfo.swift
│ ├── ViewClassInfo.swift
│ ├── TableViewInstanceInfo.swift
│ ├── ViewInstanceInfo.swift
│ └── CollectionViewInstanceInfo.swift
├── ViewControllers
│ ├── TabBarControllerClassInfo.swift
│ ├── NavigationControllerClassInfo.swift
│ ├── TabBarControllerInstanceInfo.swift
│ ├── NavigationControllerInstanceInfo.swift
│ ├── ViewControllerClassInfo.swift
│ └── ViewControllerInstanceInfo.swift
├── ViewControllerLayoutGuideInstanceInfo.swift
├── Info.plist
├── NavigationItemInstanceInfo.swift
├── SegueClassInfo.swift
├── ClassInfo.swift
├── Utility.swift
├── StoryboardFileVersionedParsers
│ └── 3.0
│ │ ├── StoryboardFile3_0Parser_Scenes.swift
│ │ ├── StoryboardFile3_0Parser.swift
│ │ ├── StoryboardFile3_0Parser_Storyboard.swift
│ │ ├── StoryboardFile3_0Parser_Segues.swift
│ │ ├── StoryboardFile3_0Parser_ViewControllers.swift
│ │ └── StoryboardFile3_0Parser_Views.swift
├── StoryboardInstanceInfo.swift
├── StoryboardFileParser.swift
├── SegueInstanceInfo.swift
└── ApplicationInfo.swift
├── StoryboardKit.podspec
├── LICENSE.md
├── .travis.yml
├── .overcommit.yml
├── CHANGELOG.md
├── README.md
└── Gemfile.lock
/fastlane/.env:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/fastlane/Scanfile:
--------------------------------------------------------------------------------
1 | clean true
2 | code_coverage true
--------------------------------------------------------------------------------
/fastlane/.env.default:
--------------------------------------------------------------------------------
1 | MAC_SDK=macosx10.11
2 |
3 | CONFIGURATION=Release
4 | SCAN_SDK=$MAC_SDK
5 |
--------------------------------------------------------------------------------
/fastlane/.env.gitsubmodules:
--------------------------------------------------------------------------------
1 | SCAN_PROJECT="StoryboardKit.xcodeproj"
2 | SCAN_SCHEME="StoryboardKit"
--------------------------------------------------------------------------------
/Cocoapod/Podfile:
--------------------------------------------------------------------------------
1 | use_frameworks!
2 |
3 | target 'CocoapodTests' do
4 | pod 'StoryboardKit', :path => '../'
5 | end
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'cocoapods'
4 | gem 'github_changelog_generator'
5 | gem 'fastlane'
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Libraries/SWXMLHash"]
2 | path = Libraries/SWXMLHash
3 | url = https://github.com/drmohundro/SWXMLHash.git
4 |
--------------------------------------------------------------------------------
/fastlane/.env.cocoapod:
--------------------------------------------------------------------------------
1 | SCAN_WORKSPACE="Cocoapod/StoryboardKit.xcworkspace"
2 | SCAN_SCHEME="CocoapodTests"
3 | SCAN_DESTINATION="arch=x86_64"
--------------------------------------------------------------------------------
/StoryboardKitTests/Images.xcassets/Zzzzzz.imageset/Zzzzzz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adorkable/StoryboardKit/master/StoryboardKitTests/Images.xcassets/Zzzzzz.imageset/Zzzzzz.png
--------------------------------------------------------------------------------
/StoryboardKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Cocoapod/StoryboardKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Tools/generateDocs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | jazzy -o docs --swift-version 2.1
4 | find ./docs/Classes/*.html | xargs grep 'Undocumented'
5 | find ./docs/Classes/**/*.html | xargs grep 'Undocumented'
6 | find ./docs/Extensions/*.html | xargs grep 'Undocumented'
7 |
--------------------------------------------------------------------------------
/Cocoapod/StoryboardKit.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/StoryboardKitTests/Images.xcassets/Zzzzzz.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Zzzzzz.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/fastlane/.env.deploy:
--------------------------------------------------------------------------------
1 | DEPLOY_BRANCH=master
2 | DEPLOY_PLIST_PATH=StoryboardKit/Info.plist
3 | DEPLOY_PODSPEC=StoryboardKit.podspec
4 | DEPLOY_REMOTE=origin
5 |
6 | DEPLOY_CHANGELOG_PATH=CHANGELOG.md
7 | DEPLOY_CHANGELOG_DELIMITER=---
8 |
9 | # Used for CHANGELOG Generation and Github Release Management
10 | GITHUB_OWNER=Adorkable
11 | GITHUB_REPOSITORY=StoryboardKit
12 | # CI Should Provide GITHUB_API_TOKEN
13 |
14 | CARTHAGE_FRAMEWORK_NAME=StoryboardKit
--------------------------------------------------------------------------------
/Cocoapod/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - StoryboardKit (0.5.9):
3 | - SWXMLHash
4 | - SWXMLHash (2.5.0)
5 |
6 | DEPENDENCIES:
7 | - StoryboardKit (from `../`)
8 |
9 | EXTERNAL SOURCES:
10 | StoryboardKit:
11 | :path: "../"
12 |
13 | SPEC CHECKSUMS:
14 | StoryboardKit: 84b859333d89d7e49beebfc3e2c8c13d9ebd4a90
15 | SWXMLHash: 04158642e0c90c52274db7914032edd41bed9a41
16 |
17 | PODFILE CHECKSUM: b29a5efaf365d56920c542e37990cb965160bc23
18 |
19 | COCOAPODS: 1.0.1
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .ruby-version
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 |
24 | # Cocoapods
25 | #
26 | Pods/
27 |
28 | # Carthage
29 | #
30 | Carthage/Checkouts
31 | Carthage/Build
32 |
33 | # Jazzy
34 | #
35 | docs/
36 |
37 | # Fastlane
38 | fastlane/report.xml
39 | fastlane/test-output
40 | fastlane/test_output
41 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 | ```
5 | sudo gem install fastlane
6 | ```
7 | # Available Actions
8 | ## Mac
9 | ### mac test_framework
10 | ```
11 | fastlane mac test_framework
12 | ```
13 | Runs all the tests
14 |
15 | ----
16 |
17 | This README.md is auto-generated and will be re-generated every time to run [fastlane](https://fastlane.tools).
18 | More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools).
19 | The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane/tree/master/fastlane).
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardKit.h
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for StoryboardKit.
12 | FOUNDATION_EXPORT double StoryboardKitVersionNumber;
13 |
14 | //! Project version string for StoryboardKit.
15 | FOUNDATION_EXPORT const unsigned char StoryboardKitVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/StoryboardKit.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "StoryboardKit"
4 | s.version = "0.5.10"
5 | s.summary = "All you would want to know about yer Storyboards"
6 |
7 | s.homepage = "https://github.com/Adorkable/StoryboardKit.git"
8 |
9 | s.author = { "Ian G" => "yo.ian.g@gmail.com" }
10 | s.platform = :osx, "10.10"
11 |
12 | s.license = "MIT"
13 |
14 | s.source = { :git => "https://github.com/Adorkable/StoryboardKit.git", :tag => s.version.to_s }
15 |
16 | s.source_files = "StoryboardKit/**/*.swift"
17 |
18 | s.requires_arc = true
19 |
20 | s.dependency 'SWXMLHash'
21 | end
22 |
--------------------------------------------------------------------------------
/StoryboardKit/Views/TableViewClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 8/26/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Table View Class that is used in your application and its storyboards
12 | public class TableViewClassInfo: ViewClassInfo {
13 | override public class var defaultClass : String { return "UITableView" }
14 |
15 | /**
16 | Default init
17 |
18 | - parameter className: name of the Class. If nil defaults to UITableView.
19 |
20 | - returns: A new TableViewClassInfo
21 | */
22 | required public init(className : String?) {
23 | super.init(className: className)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/StoryboardKit/Views/CollectionViewClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionViewClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 10/30/15.
6 | // Copyright © 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Collection View Class that is used in your application and its storyboards
12 | public class CollectionViewClassInfo: ViewClassInfo {
13 | override public class var defaultClass : String { return "UICollectionView" }
14 |
15 | /**
16 | Default init
17 |
18 | - parameter className: name of the Class. If nil defaults to UICollectionView.
19 |
20 | - returns: A new CollectionViewClassInfo
21 | */
22 | required public init(className : String?) {
23 | super.init(className: className)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/StoryboardKitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 0.5.10
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllers/TabBarControllerClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabBarControllerClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 10/15/15.
6 | // Copyright © 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Tab Bar Controller Class that is used in your application and its storyboards
12 | public class TabBarControllerClassInfo: ViewControllerClassInfo {
13 |
14 | override public class var defaultClass : String { return "UITabBarController" }
15 |
16 | /**
17 | Default init
18 |
19 | - parameter className: Name of the Tab Bar Controller class. If nil defaults to UITabBarController
20 |
21 | - returns: A new instance.
22 | */
23 | required public init(className: String?) {
24 | super.init(className: className)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllers/NavigationControllerClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationControllerClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/8/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Navigation Controller class that is used in your application and its storyboards
12 | public class NavigationControllerClassInfo: ViewControllerClassInfo {
13 | override public class var defaultClass : String { return "UINavigationController" }
14 |
15 | /**
16 | Default init
17 |
18 | - parameter className: name of the Navigation Controller class. If nil defaults to UINavigationController.
19 |
20 | - returns: A new ViewClassInfo instance
21 | */
22 | required public init(className: String?) {
23 | super.init(className: className)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllerLayoutGuideInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewControllerLayoutGuideInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/1/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a View Controller Layout Guide Instance that is used in your application and its storyboards
12 | public class ViewControllerLayoutGuideInstanceInfo: NSObject, Idable {
13 |
14 | /// Storyboard Id
15 | public let id : String
16 |
17 | /// Type - TODO: Enum
18 | public let type : String
19 |
20 | /**
21 | Default init
22 |
23 | - parameter id: Storyboard Id
24 | - parameter type: Type
25 |
26 | - returns: A new instance.
27 | */
28 | public init(id : String, type : String) {
29 | self.id = id
30 | self.type = type
31 |
32 | super.init()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/StoryboardKit/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.5.10
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | NSHumanReadableCopyright
24 | Copyright © 2015 Adorkable. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllers/TabBarControllerInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabBarControllerInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 10/15/15.
6 | // Copyright © 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Tab Bar Controller Instance that is used in your application and its storyboards
12 | public class TabBarControllerInstanceInfo: ViewControllerInstanceInfo {
13 |
14 | /**
15 | Default init
16 |
17 | - parameter classInfo: Class
18 | - parameter id: Storyboard Id
19 | - parameter storyboardIdentifier: Storyboard Identifier
20 | - parameter view: View
21 |
22 | - returns: A new instance.
23 | */
24 | public override init(classInfo : ViewControllerClassInfo, id : String, storyboardIdentifier : String?, view : ViewInstanceInfo?) {
25 |
26 | super.init(classInfo: classInfo, id: id, storyboardIdentifier: storyboardIdentifier, view: view)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/StoryboardKit/NavigationItemInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationItemInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/1/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Navigation Item Instance that is used in your application and its storyboards
12 | public class NavigationItemInstanceInfo: NSObject, Idable {
13 |
14 | /// Storyboard Id
15 | public let id : String
16 |
17 | /// Navigation Item Key
18 | public let navigationItemKey : String
19 |
20 | /// Title
21 | public let title : String
22 |
23 | /**
24 | Default init
25 |
26 | - parameter id: Storyboard Id
27 | - parameter navigationItemKey: Navigation Item Key
28 | - parameter title: Title
29 |
30 | - returns: A new instance.
31 | */
32 | init(id : String, navigationItemKey : String, title : String) {
33 | self.id = id
34 | self.navigationItemKey = navigationItemKey
35 | self.title = title
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/StoryboardKitTests/StoryboardInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardInfoTests.swift
3 | // StoryboardKitTests
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import XCTest
11 |
12 | import StoryboardKit
13 |
14 | func storyboardPathBuilder() -> String? {
15 | if let absoluteString = NSBundle(forClass: StoryboardInfoTests.self).URLForResource("StoryboardKit", withExtension: ".storyboard")?.absoluteString {
16 | return (absoluteString as NSString).stringByReplacingOccurrencesOfString("file://", withString: "")
17 | }
18 | return nil
19 | }
20 |
21 | class StoryboardInfoTests: XCTestCase {
22 | func testStoryboardPathBuilder() {
23 | let storyboardPath = storyboardPathBuilder()
24 | XCTAssertNotNil(storyboardPath, "Storyboard Path is nil")
25 |
26 | if storyboardPath != nil
27 | {
28 | let fileExists = NSFileManager.defaultManager().fileExistsAtPath(storyboardPath!)
29 | XCTAssertTrue(fileExists, "Storyboard file does not exist at path \(storyboardPath!)")
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 Ian Grossberg
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
24 |
25 |
--------------------------------------------------------------------------------
/StoryboardKit/SegueClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SegueClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/4/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Segue Class that is used in your application and its storyboards
12 | public class SegueClassInfo: ClassInfo {
13 |
14 | override public class var defaultClass : String { return "UIStoryboardSegue" }
15 |
16 | /// All instance of this class in the application
17 | public private(set) var instanceInfos = Array< StoryboardKit_WeakWrapper< SegueInstanceInfo> >()
18 |
19 | /**
20 | Default init
21 |
22 | - parameter className: Name of the Segue class. If nil defaults to UIStoryboardSegue
23 |
24 | - returns: A new instance.
25 | */
26 | required public init(className : String?) {
27 | super.init(className: className)
28 | }
29 |
30 | /**
31 | Add a Segue Instance
32 |
33 | - parameter instanceInfo: Segue Instance to add
34 | */
35 | func add(instanceInfo instanceInfo : SegueInstanceInfo) {
36 | self.instanceInfos.append( StoryboardKit_WeakWrapper(instanceInfo) )
37 | }
38 | }
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # Customise this file, documentation can be found here:
2 | # https://github.com/fastlane/fastlane/tree/master/fastlane/docs
3 | # All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md
4 | # can also be listed using the `fastlane actions` command
5 |
6 | # Change the syntax highlighting to Ruby
7 | # All lines starting with a # are ignored when running `fastlane`
8 |
9 | # If you want to automatically update fastlane if a new version is available:
10 | # update_fastlane
11 |
12 | # This is the minimum version number required.
13 | # Update this, if you use features of a newer version
14 | fastlane_version "1.95.0"
15 |
16 | default_platform :mac
17 |
18 | platform :mac do
19 |
20 | desc "Runs all the tests"
21 | lane :test_framework do
22 | scan
23 | end
24 |
25 | end
26 |
27 |
28 | # More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
29 | # All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md
30 |
31 | # fastlane reports which actions are used
32 | # No personal data is recorded. Learn more at https://github.com/fastlane/enhancer
33 |
--------------------------------------------------------------------------------
/StoryboardKitTests/ClassInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClassInfoTests.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/29/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | import StoryboardKit
12 |
13 | class ClassInfoTests: XCTestCase {
14 |
15 | func testInit() {
16 | let classInfo = ClassInfo(className: nil)
17 |
18 | XCTAssertEqual(classInfo.infoClassName, ClassInfo.defaultClass, "ClassInfo class name should be \"\(ClassInfo.defaultClass)\", was \"\(classInfo.infoClassName)\"")
19 | }
20 |
21 | func testInitCustomClassName() {
22 | let className = "Blah-dee Blah Blah"
23 |
24 | let classInfo = ClassInfo(className: className)
25 |
26 | XCTAssertEqual(classInfo.infoClassName, className, "ClassInfo class name should be \"\(className)\", was \"\(classInfo.infoClassName)\"")
27 | }
28 |
29 | func testDebugDescription() {
30 | let classInfo = ClassInfo(className: nil)
31 |
32 | let debugDescription = classInfo.debugDescription
33 |
34 | XCTAssertNotNil(debugDescription.rangeOfString("Class: "), "ClassInfo's debug description should include the class: \(debugDescription)")
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode7.3
3 | env:
4 | global:
5 | - LC_CTYPE=en_US.UTF-8
6 | - LANG=en_US.UTF-8
7 | # - FASTLANE_LANE=test_framework
8 | # matrix:
9 | # - FASTLANE_ENV=gitsubmodules
10 | # - FASTLANE_ENV=cocoapod
11 | before_install:
12 | - gem install fastlane --no-rdoc --no-ri --no-document --quiet
13 | - gem install cocoapods --no-rdoc --no-ri --no-document --quiet
14 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
15 | # - fastlane enable_crash_reporting
16 | - git submodule init
17 | script:
18 | - xcodebuild -scheme StoryboardKit -project StoryboardKit.xcodeproj -sdk 'macosx10.11' -destination 'platform=OS X' -enableCodeCoverage YES clean build test | xcpretty
19 | - cd Cocoapod && pod install && xcodebuild -scheme CocoapodTests -workspace StoryboardKit.xcworkspace -sdk 'macosx10.11' -destination 'platform=OS X' -enableCodeCoverage YES test | xcpretty && cd ..
20 | # - fastlane $FASTLANE_LANE configuration:Debug --env $FASTLANE_ENV
21 | # - fastlane $FASTLANE_LANE configuration:Release --env $FASTLANE_ENV
22 | # deploy:
23 | # provider: script
24 | # script: fastlane complete_framework_release --env deploy
25 | # on:
26 | # tags: true
27 | after_success:
28 | - bash <(curl -s https://codecov.io/bash)
29 |
--------------------------------------------------------------------------------
/StoryboardKit/Views/ViewClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/29/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | * Represents a View Class that is used in your application and its storyboards
13 | */
14 | public class ViewClassInfo: ClassInfo {
15 |
16 | override public class var defaultClass : String { return "UIView" }
17 |
18 | /// All instances of this class in the application
19 | public private(set) var instanceInfos = [StoryboardKit_WeakWrapper]()
20 |
21 | /**
22 | Default init
23 |
24 | - parameter className: name of the View class. If nil defaults to UIView.
25 |
26 | - returns: A new ViewClassInfo instance
27 | */
28 | required public init(className : String?) {
29 | super.init(className: className)
30 | }
31 |
32 | /**
33 | Add a View instance of this class
34 |
35 | - parameter instanceInfo: Instance Info of a View of this class
36 | */
37 | func add(instanceInfo instanceInfo : ViewInstanceInfo) {
38 | // TODO: prevent duplicates
39 | self.instanceInfos.append( StoryboardKit_WeakWrapper(instanceInfo) )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/StoryboardKit/ClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/29/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Class
12 | public class ClassInfo: NSObject {
13 | public class var defaultClass : String { return "" }
14 |
15 | /// Name of the Class
16 | public let infoClassName : String
17 |
18 | /**
19 | Default init
20 |
21 | - parameter className: name of the Class. If nil defaults to ClassInfo.defaultClass.
22 |
23 | - returns: A new ClassInfo instance
24 | */
25 | required public init(className : String?) {
26 |
27 | var useClassName : String
28 | if className != nil
29 | {
30 | useClassName = className!
31 | } else
32 | {
33 | useClassName = self.dynamicType.defaultClass
34 | }
35 |
36 | self.infoClassName = useClassName
37 |
38 | super.init()
39 | }
40 | }
41 |
42 | extension ClassInfo /*: CustomDebugStringConvertible*/ {
43 |
44 | /// Debug Description
45 | public override var debugDescription: String {
46 | var result = super.debugDescription
47 |
48 | result += "Class: \(self.infoClassName)"
49 |
50 | return result
51 | }
52 | }
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllers/NavigationControllerInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationControllerInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/1/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Navigation Controller Instance that is used in your application and its storyboards
12 | public class NavigationControllerInstanceInfo: ViewControllerInstanceInfo {
13 | /// Scene Member Id
14 | public let sceneMemberId : String?
15 |
16 | /// Segue to Root View
17 | public var root : SegueInstanceInfo?
18 |
19 | /**
20 | Default init
21 |
22 | - parameter classInfo: Class
23 | - parameter id: Storyboard Id
24 | - parameter storyboardIdentifier: Storyboard Identifier
25 | - parameter sceneMemberId: Scene Member Id
26 | - parameter root: Segue to Root View
27 |
28 | - returns: A new instance.
29 | */
30 | init(classInfo : NavigationControllerClassInfo, id : String, storyboardIdentifier : String?, sceneMemberId : String?/*, root : SegueInstanceInfo?*/) {
31 |
32 | self.sceneMemberId = sceneMemberId
33 | // self.root = root
34 |
35 | super.init(classInfo: classInfo, id: id, storyboardIdentifier: storyboardIdentifier, view: nil)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllers/ViewControllerClassInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewControllerClassInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | * Represents a View Controller Class that is used in your application and its storyboards
13 | */
14 | public class ViewControllerClassInfo: ClassInfo {
15 |
16 | override public class var defaultClass : String { return "UIViewController" }
17 |
18 | /// All instances of this class in the application
19 | public private(set) var instanceInfos = Array< StoryboardKit_WeakWrapper >()
20 |
21 | /**
22 | Default init
23 |
24 | - parameter className: name of the View Controller class. If nil defaults to UIViewController
25 |
26 | - returns: A new ViewControllerClassInfo instance
27 | */
28 | required public init(className : String?) {
29 | super.init(className: className)
30 | }
31 |
32 | /**
33 | Add a View Controller instance of this class
34 |
35 | - parameter instanceInfo: Instance Info of a View Controller of this class
36 | */
37 | func add(instanceInfo instanceInfo : ViewControllerInstanceInfo) {
38 | // TODO: prevent duplicates
39 | self.instanceInfos.append( StoryboardKit_WeakWrapper(instanceInfo) )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/StoryboardKit.xcodeproj/project.xcworkspace/xcshareddata/StoryboardKit.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "E9C0A5D7FC17CA9A15245CD4B5C2BFCBC98368D6",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "EB2210CFD48672E403BED699D5D7F01B844069CF" : 0,
8 | "E9C0A5D7FC17CA9A15245CD4B5C2BFCBC98368D6" : 0
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "1D91BBBC-D400-40A8-B88C-AC3B2BCD0F6E",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "EB2210CFD48672E403BED699D5D7F01B844069CF" : "StoryboardKit\/Libraries\/SWXMLHash\/",
13 | "E9C0A5D7FC17CA9A15245CD4B5C2BFCBC98368D6" : "StoryboardKit\/"
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "StoryboardKit",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "StoryboardKit.xcodeproj",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Adorkable\/StoryboardKit.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E9C0A5D7FC17CA9A15245CD4B5C2BFCBC98368D6"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/drmohundro\/SWXMLHash.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EB2210CFD48672E403BED699D5D7F01B844069CF"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/StoryboardKit/Utility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utility.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // TODO: organize appropriately, evaluate need of each
12 |
13 | // http://stackoverflow.com/a/24128121/96153
14 | /// Weak wrapper used for permanent container members that shouldn't be owners
15 | public class StoryboardKit_WeakWrapper {
16 |
17 | /// Wrapped value
18 | public weak var value : T?
19 | init (_ value: T) {
20 | self.value = value
21 | }
22 | }
23 |
24 | extension StoryboardKit_WeakWrapper : CustomDebugStringConvertible {
25 |
26 | /// Debug Description
27 | public var debugDescription: String {
28 | var result : String
29 | if let value = self.value
30 | {
31 | result = "Weak Wrapper<\(value.dynamicType)>"
32 | if let debugStringConvertable = value as? CustomDebugStringConvertible
33 | {
34 | result = result + " \(debugStringConvertable.debugDescription)"
35 | } else
36 | {
37 | result = result + " \(value)"
38 | }
39 | } else
40 | {
41 | result = "Weak Wrapper<\(self.value.dynamicType) nil"
42 | }
43 | return result
44 | }
45 | }
46 |
47 | func classWithClassName(className : String, objects : [T]) -> T? {
48 | return objects.filter( { $0.infoClassName == className } ).first
49 | }
50 |
51 | protocol Idable {
52 | var id : String { get }
53 | }
54 |
55 | func objectsWithId(id : String, objects : [T]) -> [T] {
56 | return objects.filter({ $0.id == id })
57 | }
58 |
59 | func firstObject(objects : [T]) -> T? {
60 | var result : T?
61 |
62 | if objects.count > 0 {
63 | result = objects[0]
64 | }
65 |
66 | return result
67 | }
68 |
69 | func firstObjectWithId(id : String, objects : [T]) -> T? {
70 | return firstObject( objectsWithId(id, objects: objects) )
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/Cocoapod/StoryboardKit.xcodeproj/xcshareddata/xcschemes/CocoapodTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
16 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
40 |
41 |
42 |
43 |
49 |
50 |
52 |
53 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileVersionedParsers/3.0/StoryboardFile3_0Parser_Scenes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFile3_0Parser_Scenes.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/30/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | internal extension StoryboardFile3_0Parser {
14 | // MARK: Scenes
15 |
16 | internal func parseScenes(scenes : XMLIndexer, storyboardInstanceParseInfo : StoryboardInstanceParseInfo) {
17 | for scene in scenes.children {
18 |
19 | self.parseIndividualScene(scene, storyboardInstanceParseInfo: storyboardInstanceParseInfo)
20 | }
21 | }
22 |
23 | internal func parseIndividualScene(scene : XMLIndexer, storyboardInstanceParseInfo : StoryboardInstanceParseInfo) {
24 |
25 | if let element = scene.element, let sceneId = element.allAttributes["sceneID"]?.text
26 | {
27 | let sceneInfo = StoryboardInstanceInfo.SceneInfo(sceneId: sceneId)
28 | storyboardInstanceParseInfo.add(scene: sceneInfo)
29 |
30 | let objects = scene["objects"]
31 | for object in objects.children {
32 | if let sceneObjectElement = object.element
33 | {
34 | if sceneObjectElement.name == "viewController" || sceneObjectElement.name == "tableViewController" || sceneObjectElement.name == "collectionViewController"
35 | {
36 | // TODO: seperate out VC, TVC, CVC?
37 | self.parseViewController(object, sceneInfo: sceneInfo)
38 | } else if sceneObjectElement.name == "navigationController"
39 | {
40 | self.parseNavigationController(object, sceneInfo: sceneInfo)
41 | } else if sceneObjectElement.name == "tabBarController"
42 | {
43 | self.parseTabBarController(object, sceneInfo: sceneInfo)
44 | } else
45 | {
46 | // TODO: placeholder
47 | self.Log("Skipping unsupported scene object \(sceneObjectElement.name)")
48 | }
49 | }
50 | }
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/StoryboardKitTests/StoryboardFileParserTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFileParserTests.swift
3 | // StoryboardKitTests
4 | //
5 | // Created by Ian on 5/31/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | import StoryboardKit
12 |
13 | class StoryboardFileParserTests: XCTestCase {
14 | var applicationInfo : ApplicationInfo?
15 |
16 | override func setUp() {
17 | self.continueAfterFailure = false
18 |
19 | super.setUp()
20 |
21 | applicationInfo = ApplicationInfo()
22 | }
23 |
24 | func testCannotFindStoryboardFile() {
25 | do
26 | {
27 | try StoryboardFileParser.parse(applicationInfo!, pathFileName: "asldkfjlkajdslfkajsldfkjalsdfkjlaskdjflaskjdfa.alskdjflksjf")
28 |
29 | XCTAssert(false, "Expected parse to throw an error")
30 | } catch let error as NSError
31 | {
32 | XCTAssertNotNil(error, "Expected parse to throw an error: \(error)")
33 | }
34 | }
35 |
36 | func testParseFinishes() {
37 | do
38 | {
39 | try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
40 | } catch let error as NSError
41 | {
42 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
43 | }
44 |
45 | XCTAssert(true, "Pass")
46 | }
47 |
48 | func testParseFinishedWithStoryboardInstanceInfo() {
49 | var result : StoryboardFileParser.ParseResult
50 | do
51 | {
52 | result = try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
53 | } catch let error as NSError
54 | {
55 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
56 | }
57 |
58 | XCTAssertNotNil(result.0, "returned StoryboardInstanceInfo reference is nil")
59 | }
60 |
61 | func testParseFinishesWithoutErrors() {
62 | do
63 | {
64 | try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
65 | } catch let error as NSError
66 | {
67 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/StoryboardKit/Views/TableViewInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 8/26/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Table View Instance
12 | public class TableViewInstanceInfo: ViewInstanceInfo {
13 |
14 | /// Represents a Table View Cell Prototype
15 | public class TableViewCellPrototypeInfo {
16 | /// Storyboard Id
17 | public let id : String
18 |
19 | /// Reuse Identifier
20 | public let reuseIdentifier : String?
21 |
22 | /**
23 | Default init
24 |
25 | - parameter id: Storyboard Id
26 | - parameter reuseIdentifier: Reuse Identifier
27 |
28 | - returns: A new TableViewCellPrototypeInfo instance
29 | */
30 | init(id : String, reuseIdentifier : String?) {
31 | self.id = id
32 |
33 | self.reuseIdentifier = reuseIdentifier
34 | }
35 | }
36 |
37 | /// All Cell Prototypes contained in this Table View Instance
38 | public let cellPrototypes : [TableViewCellPrototypeInfo]?
39 |
40 | /**
41 | Default init
42 |
43 | - parameter classInfo: Class
44 | - parameter id: Storyboard Id
45 | - parameter frame: Frame
46 | - parameter autoResizingMaskWidthSizable: Autoresizing Mask Width Sizable
47 | - parameter autoResizingMaskHeightSizable: Autoresizing Mask Height Sizable
48 | - parameter subviews: Subviews
49 | - parameter backgroundColor: Background Color
50 | - parameter cellPrototypes: Cell Prototypes
51 |
52 | - returns: A new CollectionViewInstanceInfo instance
53 | */
54 | init(classInfo: ViewClassInfo, id: String, frame: CGRect?, autoResizingMaskWidthSizable: Bool, autoResizingMaskHeightSizable: Bool, subviews: [ViewInstanceInfo]?, backgroundColor: NSColor?, cellPrototypes : [TableViewCellPrototypeInfo]?) {
55 |
56 | self.cellPrototypes = cellPrototypes
57 |
58 | super.init(classInfo: classInfo, id: id, frame: frame, autoResizingMaskWidthSizable: autoResizingMaskWidthSizable, autoResizingMaskHeightSizable: autoResizingMaskHeightSizable, subviews: subviews, backgroundColor: backgroundColor)
59 | }
60 | }
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | /**
14 | * Represents a Storyboard file instance
15 | */
16 | public class StoryboardInstanceInfo: NSObject {
17 |
18 | /// Use Autolayout
19 | public let useAutolayout : Bool
20 |
21 | /// Use Trait Collections
22 | public let useTraitCollections : Bool
23 |
24 | /// Initial View Controller Instance
25 | public let initialViewController : ViewControllerInstanceInfo?
26 |
27 | /// All scenes in the storyboard
28 | public private(set) var scenes = Array()
29 |
30 | /**
31 | Default init
32 |
33 | - parameter useAutolayout: Use Autolayout
34 | - parameter useTraitCollections: Use Trait Collections
35 | - parameter initialViewController: Initial View Controller Instance
36 |
37 | - returns: A new instance.
38 | */
39 | public required init(useAutolayout : Bool, useTraitCollections : Bool, initialViewController : ViewControllerInstanceInfo?) {
40 |
41 | self.useAutolayout = useAutolayout
42 | self.useTraitCollections = useTraitCollections
43 | self.initialViewController = initialViewController
44 |
45 | super.init()
46 | }
47 |
48 | /**
49 | * Represents a Scene in the storyboard
50 | */
51 | public class SceneInfo: NSObject {
52 |
53 | /// Scene Id
54 | let sceneId : String
55 |
56 | // TODO: not optional, use parsing placeholder
57 | /// View Controller
58 | public var controller : ViewControllerInstanceInfo?
59 |
60 | /// Placeholder object
61 | public var placeHolder : AnyObject?
62 |
63 | /**
64 | Default init
65 |
66 | - parameter sceneId: Scene Id
67 |
68 | - returns: A new instance.
69 | */
70 | init(sceneId : String) {
71 | self.sceneId = sceneId
72 |
73 | super.init()
74 | }
75 | }
76 |
77 | /**
78 | Add a Scene to the storyboard
79 |
80 | - parameter scene: Scene to add
81 | */
82 | func add(scene scene : SceneInfo) {
83 | // TODO: validate that it isn't a dup
84 | self.scenes.append(scene)
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/StoryboardKit/Views/ViewInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/29/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a View Instance
12 | public class ViewInstanceInfo: NSObject {
13 | /// Class
14 | public let classInfo : ViewClassInfo
15 |
16 | /// Storyboard id
17 | public let id : String
18 |
19 | /// Frame
20 | public let frame : CGRect? // TODO: should this be non-optional?
21 |
22 | /// Autoresizing Mask Width Sizable
23 | public let autoResizingMaskWidthSizable : Bool
24 |
25 | /// Autoresizing Mask Height Sizable
26 | public let autoResizingMaskHeightSizable : Bool
27 |
28 | /// Subviews
29 | public let subviews : [ViewInstanceInfo]?
30 |
31 | /// Background Color
32 | public let backgroundColor : NSColor?
33 |
34 | /**
35 | Default init
36 |
37 | - parameter classInfo: Class
38 | - parameter id: Storyboard Id
39 | - parameter frame: frame
40 | - parameter autoResizingMaskWidthSizable: Autoresizing Mask Width Sizable
41 | - parameter autoResizingMaskHeightSizable: Autoresizing Mask Height Sizable
42 | - parameter subviews: Subviews
43 | - parameter backgroundColor: Background Color
44 |
45 | - returns: A new instance.
46 | */
47 | init(classInfo : ViewClassInfo, id : String, frame : CGRect?, autoResizingMaskWidthSizable : Bool, autoResizingMaskHeightSizable : Bool, subviews : [ViewInstanceInfo]?, backgroundColor : NSColor?) {
48 | self.classInfo = classInfo
49 | self.id = id
50 |
51 | self.frame = frame
52 |
53 | self.autoResizingMaskWidthSizable = autoResizingMaskWidthSizable
54 | self.autoResizingMaskHeightSizable = autoResizingMaskHeightSizable
55 |
56 | self.subviews = subviews
57 |
58 | self.backgroundColor = backgroundColor
59 |
60 | super.init()
61 |
62 | self.classInfo.add(instanceInfo: self)
63 | }
64 | }
65 |
66 |
67 | extension ViewInstanceInfo /*: CustomDebugStringConvertible*/ {
68 |
69 | /// Debug Description
70 | override public var debugDescription : String {
71 | return super.debugDescription + "Id: \(self.id)\(self.classInfo.debugDescription)"
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/StoryboardKit/ViewControllers/ViewControllerInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewControllerInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a View Controller Instance that is used in your application and its storyboards
12 | public class ViewControllerInstanceInfo: NSObject, Idable {
13 | /// Class
14 | public let classInfo : ViewControllerClassInfo
15 |
16 | /// Storyboard Id
17 | public let id : String
18 |
19 | /// Storyboard Identifier
20 | public let storyboardIdentifier : String?
21 |
22 | /// Segues
23 | public private(set) var segues = Array< SegueInstanceInfo >()
24 |
25 | /// Layout Guides
26 | public private(set) var layoutGuides = Array< ViewControllerLayoutGuideInstanceInfo >()
27 |
28 | /// Navigation Items
29 | public private(set) var navigationItems = Array< NavigationItemInstanceInfo >()
30 |
31 | /// View
32 | public let view : ViewInstanceInfo?
33 |
34 | /**
35 | Default Init
36 |
37 | - parameter classInfo: Class
38 | - parameter id: Storyboard Id
39 | - parameter storyboardIdentifier: Storyboard Identifier
40 | - parameter view: View
41 |
42 | - returns: A new instance.
43 | */
44 | init(classInfo : ViewControllerClassInfo, id : String, storyboardIdentifier : String?, view : ViewInstanceInfo?) {
45 | self.classInfo = classInfo
46 | self.id = id
47 |
48 | self.storyboardIdentifier = storyboardIdentifier
49 |
50 | self.view = view
51 |
52 | super.init()
53 |
54 | self.classInfo.add(instanceInfo: self)
55 | }
56 |
57 | func add(segue segue : SegueInstanceInfo) {
58 | self.segues.append(segue)
59 | }
60 |
61 | func add(layoutGuide layoutGuide : ViewControllerLayoutGuideInstanceInfo) {
62 | self.layoutGuides.append(layoutGuide)
63 | }
64 |
65 | func add(navigationItem navigationItem : NavigationItemInstanceInfo) {
66 | self.navigationItems.append(navigationItem)
67 | }
68 | }
69 |
70 | extension ViewControllerInstanceInfo /*: CustomDebugStringConvertible*/ {
71 | /// Debug Description
72 | override public var debugDescription : String {
73 | return super.debugDescription + "Id: \(self.id)\(self.classInfo.debugDescription)"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/StoryboardKit/Views/CollectionViewInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionViewInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 10/30/15.
6 | // Copyright © 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Represents a Collection View Instance
12 | public class CollectionViewInstanceInfo: ViewInstanceInfo {
13 |
14 | /// Represents a Collection View Cell Prototype
15 | public class CollectionViewCellPrototypeInfo {
16 | /// Storyboard Id
17 | public let id : String
18 |
19 | /// Reuse Identifier
20 | public let reuseIdentifier : String?
21 |
22 | /**
23 | Default init
24 |
25 | - parameter id: Storyboard Id
26 | - parameter reuseIdentifier: Reuse Identifier
27 |
28 | - returns: A new CollectionViewCellPrototypeInfo instance
29 | */
30 | init(id : String, reuseIdentifier : String?) {
31 | self.id = id
32 |
33 | self.reuseIdentifier = reuseIdentifier
34 | }
35 | }
36 |
37 | /// All Cell Prototypes contained in this Collection View Instance
38 | public let cellPrototypes : [CollectionViewCellPrototypeInfo]?
39 |
40 | /**
41 | Default init
42 |
43 | - parameter classInfo: Class
44 | - parameter id: Storyboard Id
45 | - parameter frame: Frame
46 | - parameter autoResizingMaskWidthSizable: Autoresizing Mask Width Sizable
47 | - parameter autoResizingMaskHeightSizable: Autoresizing Mask Height Sizable
48 | - parameter subviews: Subviews
49 | - parameter backgroundColor: Background Color
50 | - parameter cellPrototypes: Cell Prototypes
51 |
52 | - returns: A new CollectionViewInstanceInfo instance
53 | */
54 | init(classInfo: ViewClassInfo, id: String, frame: CGRect?, autoResizingMaskWidthSizable: Bool, autoResizingMaskHeightSizable: Bool, subviews: [ViewInstanceInfo]?, backgroundColor: NSColor?, cellPrototypes : [CollectionViewCellPrototypeInfo]?) {
55 |
56 | self.cellPrototypes = cellPrototypes
57 |
58 | super.init(classInfo: classInfo, id: id, frame: frame, autoResizingMaskWidthSizable: autoResizingMaskWidthSizable, autoResizingMaskHeightSizable: autoResizingMaskHeightSizable, subviews: subviews, backgroundColor: backgroundColor)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileVersionedParsers/3.0/StoryboardFile3_0Parser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFile3_0Parser.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/31/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | /// Parser for Storyboard File Format 3.0
14 | internal class StoryboardFile3_0Parser: NSObject, StoryboardFileVersionedParser {
15 |
16 | static func supports(root: XMLIndexer) -> Bool {
17 | var result : Bool
18 |
19 | if let version = root["document"].element?.allAttributes["version"]?.text
20 | {
21 | if version == "3.0"
22 | {
23 | result = true
24 | } else
25 | {
26 | result = false
27 | }
28 | } else
29 | {
30 | result = false
31 | }
32 |
33 | return result
34 | }
35 |
36 | static func parse(indexer: XMLIndexer, applicationInfo: ApplicationInfo) throws -> StoryboardFileParser.ParseResult {
37 | let parser = StoryboardFile3_0Parser(applicationInfo: applicationInfo)
38 | return try parser.parse(indexer)
39 | }
40 |
41 | internal let applicationInfo : ApplicationInfo
42 |
43 | internal var storyboardInstanceParseInfo : StoryboardInstanceParseInfo?
44 |
45 | internal var parsedSegues = [SegueInstanceParseInfo]()
46 |
47 | internal var logs : [String]?
48 | internal func Log(message : String) {
49 | if logs == nil
50 | {
51 | logs = [String]()
52 | }
53 | logs?.append(message)
54 | }
55 |
56 | required init(applicationInfo : ApplicationInfo)
57 | {
58 | self.applicationInfo = applicationInfo
59 |
60 | super.init()
61 | }
62 |
63 | func parse(indexer : XMLIndexer) throws -> StoryboardFileParser.ParseResult {
64 | var result : StoryboardFileParser.ParseResult
65 |
66 | self.storyboardInstanceParseInfo = self.createStoryboardInstance(indexer)
67 |
68 | if let storyboardInstanceParseInfo = self.storyboardInstanceParseInfo
69 | {
70 | self.parseScenes(indexer["document"]["scenes"], storyboardInstanceParseInfo: storyboardInstanceParseInfo)
71 |
72 | self.createSegueInstanceInfosFromParsed()
73 |
74 | result = try self.createStoryboardInstanceInfoFromParsed()
75 | }
76 |
77 | return result
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Tools/matchVersiontoBranch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ $3 == '1' ]
4 | then
5 | branch=$(git rev-parse --abbrev-ref HEAD)
6 | if [[ $branch == release/* ]]
7 | then
8 | if [[ $branch =~ release/([0-9.]*)$ ]]
9 | then
10 | version=${BASH_REMATCH[1]}
11 | else
12 | exit 0
13 | fi
14 | else
15 | exit 0
16 | fi
17 | else
18 | exit 0
19 | fi
20 |
21 | root='./'
22 |
23 | plistFiles=("StoryboardKit/Info.plist")
24 | podspecFile="StoryboardKit.podspec"
25 |
26 | echo "Set Version to $version, using root $root"
27 |
28 | function updatePlist()
29 | {
30 | if [ -z "$1" ]
31 | then
32 | echo "updatePlist() expects a version for first parameter" >&2
33 | return -1
34 | fi
35 | version=$1
36 |
37 | if [ -z "$2" ]
38 | then
39 | echo "updatePlist() expects a file name for second parameter" >&2
40 | return -1
41 | fi
42 | plistFile=$2
43 |
44 | # TODO: support both PlistBuddy and plutil, test for which available
45 | #PlistBuddy "$2" Set "CFBundleShortVersionString" "$1"
46 | if plutil -replace "CFBundleShortVersionString" -string "$version" "$root/$plistFile"
47 | then
48 | echo "Updated plist file $plistFile to version $version"
49 | else
50 | return -1
51 | fi
52 |
53 | return 0
54 | }
55 |
56 | function updatePlists() {
57 | if [ -z "$1" ]
58 | then
59 | echo "updatePlists() expects a version for first parameter"
60 | return -1
61 | fi
62 | version=$1
63 |
64 | if [ -z ="$2" ]
65 | then
66 | echo "updatePlists() expects a list of PList files for second parameter"
67 | return -1
68 | fi
69 | plistFiles=$2
70 |
71 | for plistFile in ${plistFiles[@]}
72 | do
73 | if !(updatePlist "$version" "$plistFile")
74 | then
75 | echo "Error while updatingPlist($version, $plistFile)" >&2
76 | exit -1
77 | fi
78 | done
79 | }
80 |
81 | function updatePodspec()
82 | {
83 | if [ -z "$1" ]
84 | then
85 | echo "updatePodspec() expects a version for first parameter"
86 | return -1
87 | fi
88 | version=$1
89 |
90 | if [ -z ="$2" ]
91 | then
92 | echo "updatePodspec() expects a Podspec file for second parameter"
93 | return -1
94 | fi
95 | podspecFile=$2
96 |
97 | search="s/s.version = \"[0-9.]*\"/s.version = \"$version\"/g"
98 | if sed -i -e "$search" "$root/$podspecFile"
99 | then
100 | echo "Updated podspec file $podspecFile to version $version"
101 | else
102 | return -1
103 | fi
104 | return 0
105 | }
106 |
107 | if !(updatePlists "$version" "$plistFiles")
108 | then
109 | echo "Error while updatePlists($version, $plistFiles)" >&2
110 | exit -1
111 | fi
112 |
113 | if !(updatePodspec "$version" "$podspecFile")
114 | then
115 | echo "Error while updatePodspec($version, $podspecFile)" >&2
116 | exit -1
117 | fi
118 |
--------------------------------------------------------------------------------
/StoryboardKitTests/TableViewInstanceInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian Grossberg on 8/26/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | import StoryboardKit
12 |
13 | class TableViewInstanceInfoTests: XCTestCase {
14 |
15 | var applicationInfo : ApplicationInfo?
16 |
17 | var tableViewInstanceInfoId = "BYg-eK-ujo"
18 | var tableViewInstanceInfo : TableViewInstanceInfo?
19 |
20 | override func setUp() {
21 | self.continueAfterFailure = false
22 |
23 | super.setUp()
24 |
25 | applicationInfo = ApplicationInfo()
26 |
27 | do
28 | {
29 | try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
30 | } catch let error as NSError
31 | {
32 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
33 | }
34 |
35 | if let tableViewInstanceInfo = applicationInfo?.viewInstanceWithId(self.tableViewInstanceInfoId) as? TableViewInstanceInfo
36 | {
37 | self.tableViewInstanceInfo = tableViewInstanceInfo
38 | }
39 | }
40 |
41 | func testClassInfo() {
42 | let className = "UITableView"
43 | let classInfo = self.applicationInfo?.viewClassWithClassName(className)
44 |
45 | XCTAssertNotNil(self.tableViewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.tableViewInstanceInfoId)")
46 |
47 | XCTAssertNotNil(classInfo, "\(self.tableViewInstanceInfo!)'s classInfo should not be nil")
48 |
49 | XCTAssertEqual(self.tableViewInstanceInfo!.classInfo, classInfo!, "\(self.tableViewInstanceInfo!)'s classInfo should be equal to \(classInfo!)")
50 | }
51 |
52 | func testCellPrototypes() {
53 | XCTAssertNotNil(self.tableViewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.tableViewInstanceInfoId)")
54 |
55 | XCTAssertNotNil(self.tableViewInstanceInfo!.cellPrototypes, "\(self.tableViewInstanceInfo!) should contain cell prototypes")
56 | XCTAssertGreaterThan(self.tableViewInstanceInfo!.cellPrototypes!.count, 0, "\(self.tableViewInstanceInfo!)'s cell prototypes count should be greater than 0")
57 | XCTAssertNotNil(self.tableViewInstanceInfo!.cellPrototypes![0].reuseIdentifier, "\(self.tableViewInstanceInfo!.cellPrototypes![0])'s reuseIdentifier should not be nil")
58 |
59 | let reuseIdentifier = "I'm a Table Cell"
60 | XCTAssertEqual(self.tableViewInstanceInfo!.cellPrototypes![0].reuseIdentifier!, reuseIdentifier, "\(self.tableViewInstanceInfo!.cellPrototypes![0])'s reuseIdentifier should be \"\(reuseIdentifier)\"")
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFileParser.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | /**
14 | * Interface for implementing a Version Specific Storyboard File Parser
15 | */
16 | protocol StoryboardFileVersionedParser {
17 | static func supports(root : XMLIndexer) -> Bool
18 | static func parse(indexer : XMLIndexer, applicationInfo : ApplicationInfo) throws -> StoryboardFileParser.ParseResult
19 | }
20 |
21 | /**
22 | * Parses storyboard files
23 | */
24 | public class StoryboardFileParser: NSObject {
25 | /**
26 | * Result value after parsing a Storyboard file
27 | */
28 | public typealias ParseResult = (StoryboardInstanceInfo?, [String]?)
29 |
30 | /**
31 | Main parsing function
32 |
33 | - parameter applicationInfo: The applicationInfo instance you wish to fill
34 | - parameter pathFileName: The path to the Storyboard file
35 |
36 | - returns: A StoryboardInstanceInfo that represents the parsed Storyboard file and/or an error, and/or any verbose feedback, any of which non-nil or nil depending on the parsing results
37 | */
38 | public class func parse(applicationInfo : ApplicationInfo, pathFileName : String) throws -> ParseResult {
39 | var result : ParseResult
40 |
41 | if NSFileManager.defaultManager().fileExistsAtPath(pathFileName) {
42 |
43 | if let data = NSData(contentsOfFile: pathFileName)
44 | {
45 | let indexer = SWXMLHash.parse(data)
46 | result = try self.parseXML(indexer, applicationInfo: applicationInfo)
47 | } else
48 | {
49 | throw NSError(domain: "Unable to open Storyboard file \(pathFileName)", code: 0, userInfo: nil)
50 | }
51 | } else
52 | {
53 | throw NSError(domain: "Unable to find Storyboard file \(pathFileName)", code: 0, userInfo: nil)
54 | }
55 |
56 | return result
57 | }
58 |
59 | internal static let versionedParserClasses : [StoryboardFileVersionedParser.Type] = [StoryboardFile3_0Parser.self]
60 |
61 | internal class func parseXML(indexer : XMLIndexer, applicationInfo : ApplicationInfo) throws -> ParseResult {
62 | var result : ParseResult
63 |
64 | // TODO: fix to use versionsedParserClasses
65 | if StoryboardFile3_0Parser.supports(indexer)
66 | {
67 | result = try StoryboardFile3_0Parser.parse(indexer, applicationInfo: applicationInfo)
68 | } else
69 | {
70 | throw NSError(domain: "Unsupported Storyboard file format version: \(version)", code: 0, userInfo: nil)
71 | }
72 |
73 | return result
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/.overcommit.yml:
--------------------------------------------------------------------------------
1 | # Use this file to configure the Overcommit hooks you wish to use. This will
2 | # extend the default configuration defined in:
3 | # https://github.com/brigade/overcommit/blob/master/config/default.yml
4 | #
5 | # At the topmost level of this YAML file is a key representing type of hook
6 | # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
7 | # customize each hook, such as whether to only run it on certain files (via
8 | # `include`), whether to only display output if it fails (via `quiet`), etc.
9 | #
10 | # For a complete list of hooks, see:
11 | # https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook
12 | #
13 | # For a complete list of options that you can use to customize hooks, see:
14 | # https://github.com/brigade/overcommit#configuration
15 | #
16 | # Uncomment the following lines to make the configuration take effect.
17 |
18 | #PreCommit:
19 | # RuboCop:
20 | # enabled: true
21 | # on_warn: fail # Treat all warnings as failures
22 | #
23 | # TrailingWhitespace:
24 | # exclude:
25 | # - '**/db/structure.sql' # Ignore trailing whitespace in generated files
26 | #
27 | #PostCheckout:
28 | # ALL: # Special hook name that customizes all hooks of this type
29 | # quiet: true # Change all post-checkout hooks to only display output on failure
30 | #
31 | # IndexTags:
32 | # enabled: true # Generate a tags file with `ctags` each time HEAD changes
33 |
34 | CommitMsg:
35 | ALL:
36 | enabled: false
37 | EmptyMessage:
38 | enabled: true
39 | HardTabs:
40 | enabled: true
41 |
42 | PostCheckout:
43 | ALL:
44 | enabled: false
45 | BundleInstall:
46 | enabled: true
47 | SubmoduleStatus:
48 | enabled: true
49 | MatchVersionToBranch:
50 | enabled: true
51 | required_executable: './Tools/matchVersiontoBranch.sh'
52 |
53 | PostCommit:
54 | ALL:
55 | enabled: false
56 | BundleInstall:
57 | enabled: true
58 | SubmoduleStatus:
59 | enabled: true
60 | GitGuilt:
61 | enabled: true
62 |
63 | PostMerge:
64 | ALL:
65 | enabled: false
66 | BundleInstall:
67 | enabled: true
68 | SubmoduleStatus:
69 | enabled: true
70 |
71 | PostRewrite:
72 | ALL:
73 | enabled: false
74 | BundleInstall:
75 | enabled: true
76 | SubmoduleStatus:
77 | enabled: true
78 |
79 | PreCommit:
80 | ALL:
81 | enabled: false
82 | AuthorEmail:
83 | enabled: true
84 | BrokenSymlinks:
85 | enabled: true
86 | # BundleCheck:
87 | # enabled: true
88 | CaseConflicts:
89 | enabled: true
90 | GoLint:
91 | enabled: true
92 | GoVet:
93 | enabled: true
94 | JsonSyntax:
95 | enabled: true
96 | LocalPathsInGemfile:
97 | enabled: true
98 | MergeConflicts:
99 | enabled: true
100 | TravisLint:
101 | enabled: true
102 |
103 | PrePush:
104 | ALL:
105 | enabled: false
106 |
107 | PreRebase:
108 | ALL:
109 | enabled: false
110 |
111 |
--------------------------------------------------------------------------------
/StoryboardKit/SegueInstanceInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SegueInstanceInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // TODO: should we keep it weak? should we be using the weak attribute?
12 | public typealias SegueConnection = StoryboardKit_WeakWrapper
13 |
14 | /// Represents a Segue Instance used in your application and its storyboards
15 | public class SegueInstanceInfo: NSObject, Idable {
16 |
17 | /// Class
18 | public let classInfo : SegueClassInfo
19 |
20 | /// Storyboard Id
21 | public let id : String
22 |
23 | /// Source
24 | public let source : SegueConnection
25 |
26 | /// Destination
27 | public let destination : SegueConnection
28 |
29 | /// Kind of Segue
30 | public let kind : String?
31 |
32 | /// Identifier
33 | public let identifier : String?
34 |
35 | /**
36 | Default init
37 |
38 | - parameter classInfo: Class
39 | - parameter id: Storyboard Id
40 | - parameter source: Source
41 | - parameter destination: Destination
42 | - parameter kind: Kind of Segue
43 | - parameter identifier: Identifier
44 |
45 | - returns: A new instance.
46 | */
47 | public init(classInfo : SegueClassInfo, id : String, source : SegueConnection, destination : SegueConnection, kind : String?, identifier : String?) {
48 | self.classInfo = classInfo
49 | self.id = id
50 | self.source = source
51 | self.destination = destination
52 | self.kind = kind
53 | self.identifier = identifier
54 |
55 | super.init()
56 |
57 | self.classInfo.add(instanceInfo: self)
58 | }
59 |
60 | /**
61 | Convenience init: Destination as a View Controller Instance
62 |
63 | - parameter classInfo: Class
64 | - parameter id: Storyboard Id
65 | - parameter source: Source as SegueConnection
66 | - parameter destination: Destination as View Controller Instance
67 | - parameter kind: Kind of Segue
68 | - parameter identifier: Identifier
69 |
70 | - returns: A new instance.
71 | */
72 | public convenience init(classInfo : SegueClassInfo, id : String, source : SegueConnection, destination : ViewControllerInstanceInfo, kind : String?, identifier : String?) {
73 | self.init(classInfo: classInfo, id: id, source: source, destination: StoryboardKit_WeakWrapper(destination), kind: kind, identifier: identifier)
74 | }
75 | }
76 |
77 | extension SegueInstanceInfo /*: CustomDebugStringConvertible*/ {
78 |
79 | /// Debug Description
80 | override public var debugDescription : String {
81 | get {
82 | var result = super.debugDescription
83 |
84 | result += "\n\(self.classInfo)"
85 | result += "\nId: \(self.id)"
86 | result += "\nSource: \(self.source.value)"
87 | result += "\nDestination: \(self.destination.value)"
88 | result += "\nKind: \(self.kind)"
89 | result += "\nIdentifier: \(self.identifier)"
90 |
91 | return result
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/StoryboardKitTests/ApplicationInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ApplicationInfoTests.swift
3 | // StoryboardKitTests
4 | //
5 | // Created by Ian on 5/31/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | import StoryboardKit
12 |
13 | class ApplicationInfoTests: XCTestCase {
14 | var applicationInfo : ApplicationInfo?
15 |
16 | override func setUp() {
17 | super.setUp()
18 |
19 | applicationInfo = ApplicationInfo()
20 |
21 | do
22 | {
23 | try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
24 | } catch let error as NSError
25 | {
26 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
27 | }
28 | }
29 |
30 | func testViewControllerClassWithClassName() {
31 | let className = "UIViewController"
32 | let classInfo = applicationInfo!.viewControllerClassWithClassName(className)
33 | XCTAssertNotNil(classInfo, "Expected a classInfo for '\(className)' class")
34 | }
35 |
36 | func testViewControllerInstanceWithInstanceId() {
37 | let id = "yrP-vr-uHE"
38 | let instanceInfo = applicationInfo?.viewControllerInstanceWithId(id)
39 | XCTAssertNotNil(instanceInfo, "Expected an instanceInfo for id '\(id)'")
40 | }
41 |
42 | func testViewControllerInstanceWithStoryboardIdentifier() {
43 | let storyboardIdentifier = "FirstInstance"
44 | let instanceInfo = applicationInfo?.viewControllerInstanceWithStoryboardIdentifier(storyboardIdentifier)
45 | XCTAssertNotNil(instanceInfo, "Expected an instanceInfo for storyboard identifier '\(storyboardIdentifier)'")
46 | }
47 |
48 | func testNavigationControllerInstanceWithId() {
49 | let id = "eGU-XO-Tph"
50 | let instanceInfo = applicationInfo?.navigationControllerInstanceWithId(id)
51 | XCTAssertNotNil(instanceInfo, "Expected an instanceInfo for id '\(id)'")
52 | }
53 |
54 | func testNavigationControllerInstanceWithStoryboardIdentifier() {
55 | let storyboardIdentifier = "Navigation"
56 | let instanceInfo = applicationInfo?.navigationControllerInstanceWithStoryboardIdentifier(storyboardIdentifier)
57 | XCTAssertNotNil(instanceInfo, "Expected an instanceInfo for storyboard identifier '\(storyboardIdentifier)'")
58 | }
59 |
60 | func testSegueClassWithClassName() {
61 | let className = "UIStoryboardSegue"
62 | let classInfo = applicationInfo?.segueClassWithClassName(className)
63 | XCTAssertNotNil(classInfo, "Expected a classInfo for '\(className)' class")
64 | }
65 |
66 | func testViewClassWithClassName() {
67 | let className = "UIView"
68 | let classInfo = applicationInfo?.viewClassWithClassName(className)
69 | XCTAssertNotNil(classInfo, "Expected a classInfo for '\(className)' class")
70 | }
71 |
72 | func testViewClassWithCustomClassName() {
73 | let className = "CustomButton"
74 | let classInfo = applicationInfo?.viewClassWithClassName(className)
75 | XCTAssertNotNil(classInfo, "Expected a classInfo for '\(className)' class")
76 | }
77 |
78 | func testViewInstanceWithId() {
79 | let id = "IKn-pG-61R"
80 | let instanceInfo = applicationInfo?.viewInstanceWithId(id)
81 | XCTAssertNotNil(instanceInfo, "Expected an instanceInfo for id '\(id)'")
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/StoryboardKitTests/StoryboardInstanceInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardInstanceInfoTests.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/29/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | import StoryboardKit
12 |
13 | class StoryboardInstanceInfoTests: XCTestCase {
14 | var applicationInfo : ApplicationInfo?
15 |
16 | override func setUp() {
17 | self.continueAfterFailure = false
18 |
19 | super.setUp()
20 |
21 | applicationInfo = ApplicationInfo()
22 | }
23 |
24 | // TODO: test that false is being store
25 | func testUseAutolayout() {
26 | var result : StoryboardFileParser.ParseResult
27 |
28 | do
29 | {
30 | result = try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
31 | } catch let error as NSError
32 | {
33 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
34 | }
35 |
36 | XCTAssertNotNil(result.0, "returned StoryboardInstanceInfo reference is nil")
37 |
38 | let storyboardInstanceInfo = result.0!
39 |
40 | XCTAssertTrue(storyboardInstanceInfo.useAutolayout, "Expected useAutolayout in \(storyboardInstanceInfo) to be true")
41 | }
42 |
43 | // TODO: test that false is being store
44 | func testUseTraitCollections() {
45 | var result : StoryboardFileParser.ParseResult
46 |
47 | do
48 | {
49 | result = try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
50 | } catch let error as NSError
51 | {
52 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
53 | }
54 | XCTAssertNotNil(result.0, "returned StoryboardInstanceInfo reference is nil")
55 |
56 | let storyboardInstanceInfo = result.0!
57 |
58 | XCTAssertTrue(storyboardInstanceInfo.useTraitCollections, "Expected useTraitCollections in \(storyboardInstanceInfo) to be true")
59 | }
60 |
61 | func testInitialViewController() {
62 | var result : StoryboardFileParser.ParseResult
63 |
64 | do
65 | {
66 | result = try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
67 | } catch let error as NSError
68 | {
69 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
70 | }
71 |
72 | XCTAssertNotNil(result.0, "returned StoryboardInstanceInfo reference is nil")
73 |
74 | let storyboardInstanceInfo = result.0!
75 |
76 | XCTAssertNotNil(storyboardInstanceInfo.initialViewController, "Expected StoryboardInstanceInfo to contain an initialViewController")
77 |
78 | let firstInstanceStoryboardIdentifier = "FirstInstance"
79 | let firstInstance = applicationInfo?.viewControllerInstanceWithStoryboardIdentifier(firstInstanceStoryboardIdentifier)
80 | XCTAssertNotNil(firstInstance, "Test Failure: Expected ApplicationInfo to contain a View Controller with Storyboard Identifier \(firstInstanceStoryboardIdentifier)")
81 | XCTAssertEqual(storyboardInstanceInfo.initialViewController!, firstInstance!, "Expected StoryboardInstanceInfo's initialViewController to be \(firstInstance!), instead it was \(storyboardInstanceInfo.initialViewController!)")
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [0.5.7](https://github.com/Adorkable/StoryboardKit/tree/0.5.7) (2016-08-09)
4 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.6...0.5.7)
5 |
6 | ## [0.5.6](https://github.com/Adorkable/StoryboardKit/tree/0.5.6) (2015-12-15)
7 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.5...0.5.6)
8 |
9 | **Implemented enhancements:**
10 |
11 | - Github Releases through Travis [\#15](https://github.com/Adorkable/StoryboardKit/issues/15)
12 |
13 | ## [0.5.5](https://github.com/Adorkable/StoryboardKit/tree/0.5.5) (2015-11-14)
14 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.4...0.5.5)
15 |
16 | **Implemented enhancements:**
17 |
18 | - Changelogs! [\#14](https://github.com/Adorkable/StoryboardKit/issues/14)
19 |
20 | ## [0.5.4](https://github.com/Adorkable/StoryboardKit/tree/0.5.4) (2015-11-14)
21 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.3...0.5.4)
22 |
23 | **Implemented enhancements:**
24 |
25 | - Parse View tree [\#12](https://github.com/Adorkable/StoryboardKit/issues/12)
26 | - appledocs/jazzy docs [\#7](https://github.com/Adorkable/StoryboardKit/issues/7)
27 | - Hook up to Travis CI [\#6](https://github.com/Adorkable/StoryboardKit/issues/6)
28 | - Do not require a StoryboardInstanceInfo to parse a storyboard file [\#4](https://github.com/Adorkable/StoryboardKit/issues/4)
29 |
30 | **Fixed bugs:**
31 |
32 | - fix Travis CI Test Failure [\#13](https://github.com/Adorkable/StoryboardKit/issues/13)
33 |
34 | ## [0.5.3](https://github.com/Adorkable/StoryboardKit/tree/0.5.3) (2015-11-03)
35 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.2...0.5.3)
36 |
37 | ## [0.5.2](https://github.com/Adorkable/StoryboardKit/tree/0.5.2) (2015-11-02)
38 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.1...0.5.2)
39 |
40 | ## [0.5.1](https://github.com/Adorkable/StoryboardKit/tree/0.5.1) (2015-11-02)
41 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.5.0...0.5.1)
42 |
43 | ## [0.5.0](https://github.com/Adorkable/StoryboardKit/tree/0.5.0) (2015-10-31)
44 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.4.1...0.5.0)
45 |
46 | ## [0.4.1](https://github.com/Adorkable/StoryboardKit/tree/0.4.1) (2015-10-15)
47 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.4.0...0.4.1)
48 |
49 | ## [0.4.0](https://github.com/Adorkable/StoryboardKit/tree/0.4.0) (2015-09-19)
50 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.3.2...0.4.0)
51 |
52 | ## [0.3.2](https://github.com/Adorkable/StoryboardKit/tree/0.3.2) (2015-09-11)
53 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.3.1...0.3.2)
54 |
55 | ## [0.3.1](https://github.com/Adorkable/StoryboardKit/tree/0.3.1) (2015-09-11)
56 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.3.0...0.3.1)
57 |
58 | ## [0.3.0](https://github.com/Adorkable/StoryboardKit/tree/0.3.0) (2015-08-26)
59 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.2.0...0.3.0)
60 |
61 | ## [0.2.0](https://github.com/Adorkable/StoryboardKit/tree/0.2.0) (2015-08-22)
62 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.1.1...0.2.0)
63 |
64 | ## [0.1.1](https://github.com/Adorkable/StoryboardKit/tree/0.1.1) (2015-06-24)
65 | [Full Changelog](https://github.com/Adorkable/StoryboardKit/compare/0.1.0...0.1.1)
66 |
67 | ## [0.1.0](https://github.com/Adorkable/StoryboardKit/tree/0.1.0) (2015-06-24)
68 |
69 |
70 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | StoryboardKit
2 | ===
3 | [](https://travis-ci.org/Adorkable/StoryboardKit)
4 | [](http://codecov.io/github/Adorkable/StoryboardKit?branch=master)
5 | [](http://cocoadocs.org/docsets/StoryboardKit/)
6 | [](http://cocoadocs.org/docsets/StoryboardKit/)
7 | [](http://cocoadocs.org/docsets/StoryboardKit/)
8 | [](https://app.fossa.io/projects/git%2Bgithub.com%2FAdorkable%2FStoryboardKit?ref=badge_shield)
9 |
10 | **StoryboardKit** a simple OSX library that tells you all you would want to know about storyboard files.
11 |
12 | Currently it supports iOS storyboards only. OSX storyboard support forthcoming!
13 |
14 | Installation
15 | ---
16 | ---
17 | **StoryboardKit** is available through **[cocoapods](http://cocoapods.org)**, to install simple add the following line to your `PodFile`:
18 |
19 | ``` ruby
20 | pod "StoryboardKit"
21 | ```
22 |
23 | Alternatively you can add the **[github repo](https://github.com/Adorkable/StoryboardKit)** as a submodule and use **StoryboardKit** as a framework.
24 |
25 | Carthage support soon!
26 |
27 | Setup and Usage
28 | ---
29 | ---
30 | The library uses two "root" level objects to provide the tree of information you'll need:
31 |
32 | * `ApplicationInfo` - contains all information global to your application such as class information as well as instance information
33 | * `StoryboardInfo` - contains all information specific to a particular Storyboard file
34 |
35 | To parse a Storyboard file:
36 |
37 | ``` swift
38 | var applicationInfo = ApplicationInfo()
39 | var storyboardInfo = StoryboardFileParser.parse(applicationInfo!, pathFileName: "Main.storyboard")
40 | ```
41 |
42 | From here you can access things like the list of all **ViewControllerClassInfo**s or **ViewControllerInstanceInfo**s in the app through your **ApplicationInfo** instance
43 |
44 | ``` swift
45 | for viewControllerClass in application.viewControllerClasses {
46 | ...
47 | }
48 | ```
49 |
50 | Or perhaps you'll traverse through your Storyboard graph via the **StoryboardInstanceInfo**'s **initialViewController** or **scenes** list.
51 |
52 | ``` swift
53 | guard let initialViewController = storyboardInfo.initialViewController else { ... }
54 | guard let initialView = initialViewController.view else { ... }
55 |
56 | guard let subviews = initialView.subviews else { ... }
57 |
58 | for subview in subviews {
59 | ...
60 | }
61 | ```
62 |
63 | To learn more about the information **StoryboardKit** currently parses please read the docs here: [cocoadocs.org](http://cocoadocs.org/docsets/StoryboardKit/)
64 |
65 | To see an example of **StoryboardKit** in use check out the _seguecode_ repo here: [seguecode](https://github.com/Adorkable/seguecode)
66 |
67 | Contributing
68 | ---
69 | If you have any ideas, suggestions or bugs to report please [create an issue](https://github.com/Adorkable/StoryboardKit/issues/new) labeled *feature* or *bug* (check to see if the issue exists first please!).
70 |
71 | Or submit a pull request, there is a lot more work to be done!
72 |
73 |
74 | ## License
75 | [](https://app.fossa.io/projects/git%2Bgithub.com%2FAdorkable%2FStoryboardKit?ref=badge_large)
--------------------------------------------------------------------------------
/StoryboardKitTests/ViewInstanceInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewInstanceInfoTests.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/30/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | import StoryboardKit
12 |
13 | class ViewInstanceInfoTests: XCTestCase {
14 | var applicationInfo : ApplicationInfo?
15 |
16 | var viewInstanceInfoId = "IKn-pG-61R"
17 | var viewInstanceInfo : ViewInstanceInfo?
18 |
19 | override func setUp() {
20 | self.continueAfterFailure = false
21 |
22 | super.setUp()
23 |
24 | applicationInfo = ApplicationInfo()
25 |
26 | do
27 | {
28 | try StoryboardFileParser.parse(applicationInfo!, pathFileName: storyboardPathBuilder()! )
29 | } catch let error as NSError
30 | {
31 | XCTAssertNil(error, "Expected parse to not throw an error: \(error)")
32 | }
33 |
34 | self.viewInstanceInfo = applicationInfo?.viewInstanceWithId(self.viewInstanceInfoId)
35 | }
36 |
37 | func testClassInfo() {
38 | let className = "UIView"
39 | let classInfo = self.applicationInfo?.viewClassWithClassName(className)
40 |
41 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
42 |
43 | XCTAssertNotNil(classInfo, "\(self.viewInstanceInfo!)'s classInfo should not be nil")
44 |
45 | XCTAssertEqual(self.viewInstanceInfo!.classInfo, classInfo!, "\(self.viewInstanceInfo!)'s classInfo should be equal to \(classInfo!)")
46 | }
47 |
48 | func testId() {
49 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
50 |
51 | XCTAssertEqual(self.viewInstanceInfo!.id, self.viewInstanceInfoId, "\(self.viewInstanceInfo!)'s id should be equal to \(self.viewInstanceInfo)")
52 | }
53 |
54 | func testFrame() {
55 | let equalTo = CGRect(x: 0, y: 0, width: 600, height: 600)
56 |
57 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
58 | // XCTAssertNotNil(self.viewInstanceInfo!.frame, "\(self.viewInstanceInfo)'s frame should not be nil")
59 |
60 | XCTAssertEqual(self.viewInstanceInfo!.frame!, equalTo, "\(self.viewInstanceInfo!)'s frame should be equal to \(equalTo)")
61 | }
62 |
63 | func testAutoResizingMaskWidthSizable() {
64 | let equalTo = true
65 |
66 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
67 |
68 | XCTAssertEqual(self.viewInstanceInfo!.autoResizingMaskWidthSizable, equalTo, "\(self.viewInstanceInfo!)'s autoResizingMaskWidthSizable should be equal to \(equalTo)")
69 | }
70 |
71 | func testAutoResizingMaskHeightSizable() {
72 | let equalTo = true
73 |
74 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
75 |
76 | XCTAssertEqual(self.viewInstanceInfo!.autoResizingMaskHeightSizable, equalTo, "\(self.viewInstanceInfo!)'s autoResizingMaskHeightSizable should be equal to \(equalTo)")
77 | }
78 |
79 | func testSubviews() {
80 | let equalTo = 4
81 |
82 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
83 |
84 | XCTAssertNotNil(self.viewInstanceInfo!.subviews, "\(self.viewInstanceInfo!)'s subviews should not be nil")
85 | XCTAssertEqual(self.viewInstanceInfo!.subviews!.count, equalTo, "\(self.viewInstanceInfo!)'s subview count should be equal to \(equalTo)")
86 | }
87 |
88 | func testBackgroundColor() {
89 | let equalTo = NSColor(calibratedWhite: 0.66666666666666663, alpha: 1.0)
90 |
91 | XCTAssertNotNil(self.viewInstanceInfo, "Unable to retrieve ViewInstanceInfo with id \(self.viewInstanceInfoId)")
92 |
93 | XCTAssertNotNil(self.viewInstanceInfo!.backgroundColor, "\(self.viewInstanceInfo!)'s background color should not be nil")
94 | XCTAssertEqual(self.viewInstanceInfo!.backgroundColor!, equalTo, "\(self.viewInstanceInfo!)'s background color count should be equal to \(equalTo)")
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileVersionedParsers/3.0/StoryboardFile3_0Parser_Storyboard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFile3_0Parser_Storyboard.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/30/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | internal extension StoryboardFile3_0Parser {
14 |
15 |
16 | // MARK: Storyboard
17 |
18 | internal class StoryboardInstanceParseInfo : NSObject {
19 | // internal var fileType : String
20 | // internal var fileVersion : String
21 | // internal var toolsVersion : String
22 | // internal var systemVersion : String
23 | // internal var targetRuntime : String
24 | // internal var propertyAccessControl : String
25 |
26 | internal var useAutolayout : Bool
27 | internal var useTraitCollections : Bool
28 | internal var initialViewControllerId : String?
29 |
30 | init(useAutolayout : Bool, useTraitCollections : Bool, initialViewControllerId : String?) {
31 | self.useAutolayout = useAutolayout
32 | self.useTraitCollections = useTraitCollections
33 | self.initialViewControllerId = initialViewControllerId
34 |
35 | super.init()
36 | }
37 |
38 | var scenes : [StoryboardInstanceInfo.SceneInfo] = Array()
39 |
40 | func add(scene scene : StoryboardInstanceInfo.SceneInfo) {
41 | // TODO: validate that it isn't a dup
42 | self.scenes.append(scene)
43 | }
44 | }
45 |
46 | internal func createStoryboardInstance(root : XMLIndexer) -> StoryboardInstanceParseInfo? {
47 | var result : StoryboardInstanceParseInfo?
48 |
49 | if let document = root["document"].element
50 | {
51 | let useAutolayout = document.allAttributes["useAutolayout"]?.text == "YES"
52 | let useTraitCollections = document.allAttributes["useTraitCollections"]?.text == "YES"
53 |
54 | let initialViewControllerId = document.allAttributes["initialViewController"]?.text
55 |
56 |
57 | let storyboardInstance = StoryboardInstanceParseInfo(useAutolayout: useAutolayout, useTraitCollections: useTraitCollections, initialViewControllerId: initialViewControllerId)
58 |
59 | // TODO: StoryboardFileInfo
60 | // storyboardInstance.fileType = document.attributes["type"]
61 | // storyboardInstance.fileVersion = document.attributes["version"]
62 | // storyboardInstance.toolsVersion = document.attributes["toolsVersion"]
63 | // storyboardInstance.systemVersion = document.attributes["systemVersion"]
64 | // storyboardInstance.targetRuntime = document.attributes["targetRuntime"]
65 | // storyboardInstance.propertyAccessControl = document.attributes["propertyAccessControl"]
66 |
67 | result = storyboardInstance
68 | }
69 |
70 | return result
71 | }
72 |
73 | internal func createStoryboardInstanceInfoFromParsed() throws -> StoryboardFileParser.ParseResult {
74 | var result : StoryboardFileParser.ParseResult
75 |
76 | if let storyboardInstanceParseInfo = self.storyboardInstanceParseInfo
77 | {
78 | var initialViewController : ViewControllerInstanceInfo?
79 |
80 | if let initialViewControllerId = storyboardInstanceParseInfo.initialViewControllerId
81 | {
82 | initialViewController = self.applicationInfo.viewControllerInstanceWithId(initialViewControllerId)
83 | }
84 |
85 | let storyboardInstanceInfo = StoryboardInstanceInfo(useAutolayout: storyboardInstanceParseInfo.useAutolayout, useTraitCollections: storyboardInstanceParseInfo.useTraitCollections, initialViewController: initialViewController)
86 |
87 | for sceneInfo in storyboardInstanceParseInfo.scenes
88 | {
89 | storyboardInstanceInfo.add(scene: sceneInfo)
90 | }
91 |
92 | result = (storyboardInstanceInfo, self.logs)
93 | } else
94 | {
95 | throw NSError(domain: "Unable to find StoryboardInstanceParseInfo, likely cause was we were unable to parse root of Storyboard file", code: 0, userInfo: nil)
96 | }
97 |
98 | return result
99 | }
100 | }
--------------------------------------------------------------------------------
/StoryboardKit.xcodeproj/xcshareddata/xcschemes/StoryboardKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
104 |
105 |
106 |
107 |
109 |
110 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileVersionedParsers/3.0/StoryboardFile3_0Parser_Segues.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFile3_0Parser_Segues.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/30/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | internal extension StoryboardFile3_0Parser {
14 | // MARK: Segues
15 |
16 | internal class SegueInstanceParseInfo : NSObject/*, CustomDebugStringConvertible*/ {
17 | internal let classInfo : SegueClassInfo
18 | internal let id : String
19 | internal var source : SegueConnection
20 | internal let kind : String?
21 | internal let identifier : String?
22 | internal let destinationId : String
23 | internal var destination : SegueConnection?
24 |
25 | init(classInfo : SegueClassInfo, id : String, source : SegueConnection, destinationId : String, kind : String?, identifier : String?) {
26 | self.classInfo = classInfo
27 | self.id = id
28 | self.source = source
29 | self.destinationId = destinationId
30 | self.kind = kind
31 | self.identifier = identifier
32 |
33 | super.init()
34 | }
35 |
36 | override var debugDescription : String {
37 | var result : String = super.debugDescription
38 |
39 | if let identifier = self.identifier
40 | {
41 | result += identifier
42 | }
43 |
44 | return result
45 | }
46 | }
47 |
48 | internal func createConnectionParseInfo(connection : XMLIndexer, source : ViewControllerInstanceInfo) -> SegueInstanceParseInfo? {
49 | var result : SegueInstanceParseInfo?
50 |
51 | if let element = connection.element,
52 | let id = element.allAttributes["id"]?.text,
53 | let destinationId = element.allAttributes["destination"]?.text
54 | {
55 | var useClass : String
56 | if let customClass = element.allAttributes["customClass"]?.text
57 | {
58 | useClass = customClass
59 | } else
60 | {
61 | useClass = SegueClassInfo.defaultClass
62 | }
63 |
64 | var segueClass = self.applicationInfo.segueClassWithClassName(useClass)
65 | if segueClass == nil
66 | {
67 | segueClass = SegueClassInfo(className: useClass)
68 | self.applicationInfo.add(segueClass: segueClass!)
69 | }
70 |
71 | let kind = element.allAttributes["kind"]?.text
72 | let identifier = element.allAttributes["identifier"]?.text
73 |
74 | result = SegueInstanceParseInfo(classInfo: segueClass!, id: id, source: StoryboardKit_WeakWrapper(source), destinationId: destinationId, kind: kind, identifier: identifier)
75 | }
76 |
77 | return result
78 | }
79 |
80 | internal func createSegueInstanceInfosFromParsed() {
81 | while self.parsedSegues.count > 0
82 | {
83 | let segueParsedInfo = self.parsedSegues.removeLast()
84 |
85 | var segueInfo : SegueInstanceInfo?
86 |
87 | if let destination = self.applicationInfo.viewControllerInstanceWithId(segueParsedInfo.destinationId)
88 | {
89 | segueInfo = SegueInstanceInfo(classInfo: segueParsedInfo.classInfo, id: segueParsedInfo.id, source: segueParsedInfo.source, destination: destination, kind: segueParsedInfo.kind, identifier: segueParsedInfo.identifier)
90 | } else if let destination = self.applicationInfo.navigationControllerInstanceWithId(segueParsedInfo.destinationId)
91 | {
92 | segueInfo = SegueInstanceInfo(classInfo: segueParsedInfo.classInfo, id: segueParsedInfo.id, source: segueParsedInfo.source, destination: destination, kind: segueParsedInfo.kind, identifier: segueParsedInfo.identifier)
93 | } else if let destination = self.applicationInfo.tabBarControllerInstanceWithId(segueParsedInfo.destinationId)
94 | {
95 | segueInfo = SegueInstanceInfo(classInfo: segueParsedInfo.classInfo, id: segueParsedInfo.id, source: segueParsedInfo.source, destination: destination, kind: segueParsedInfo.kind, identifier: segueParsedInfo.identifier)
96 | } else
97 | {
98 | self.Log("Error linking pending segues, unable to find destination with id \(segueParsedInfo.destinationId)")
99 | }
100 |
101 | if segueInfo != nil {
102 | if segueInfo!.kind == "relationship" && segueInfo!.source.value is NavigationControllerInstanceInfo {
103 | (segueInfo!.source.value as! NavigationControllerInstanceInfo).root = segueInfo
104 | } else {
105 | segueInfo!.source.value!.add(segue: segueInfo!)
106 | }
107 | }
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.1)
5 | activesupport (4.2.11.1)
6 | i18n (~> 0.7)
7 | minitest (~> 5.1)
8 | thread_safe (~> 0.3, >= 0.3.4)
9 | tzinfo (~> 1.1)
10 | addressable (2.8.0)
11 | public_suffix (>= 2.0.2, < 5.0)
12 | atomos (0.1.3)
13 | babosa (1.0.2)
14 | claide (1.0.3)
15 | cocoapods (1.7.5)
16 | activesupport (>= 4.0.2, < 5)
17 | claide (>= 1.0.2, < 2.0)
18 | cocoapods-core (= 1.7.5)
19 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
20 | cocoapods-downloader (>= 1.2.2, < 2.0)
21 | cocoapods-plugins (>= 1.0.0, < 2.0)
22 | cocoapods-search (>= 1.0.0, < 2.0)
23 | cocoapods-stats (>= 1.0.0, < 2.0)
24 | cocoapods-trunk (>= 1.3.1, < 2.0)
25 | cocoapods-try (>= 1.1.0, < 2.0)
26 | colored2 (~> 3.1)
27 | escape (~> 0.0.4)
28 | fourflusher (>= 2.3.0, < 3.0)
29 | gh_inspector (~> 1.0)
30 | molinillo (~> 0.6.6)
31 | nap (~> 1.0)
32 | ruby-macho (~> 1.4)
33 | xcodeproj (>= 1.10.0, < 2.0)
34 | cocoapods-core (1.7.5)
35 | activesupport (>= 4.0.2, < 6)
36 | fuzzy_match (~> 2.0.4)
37 | nap (~> 1.0)
38 | cocoapods-deintegrate (1.0.4)
39 | cocoapods-downloader (1.6.3)
40 | cocoapods-plugins (1.0.0)
41 | nap
42 | cocoapods-search (1.0.0)
43 | cocoapods-stats (1.1.0)
44 | cocoapods-trunk (1.4.0)
45 | nap (>= 0.8, < 2.0)
46 | netrc (~> 0.11)
47 | cocoapods-try (1.1.0)
48 | colored (1.2)
49 | colored2 (3.1.2)
50 | commander-fastlane (4.4.6)
51 | highline (~> 1.7.2)
52 | concurrent-ruby (1.1.5)
53 | declarative (0.0.10)
54 | declarative-option (0.1.0)
55 | digest-crc (0.4.1)
56 | domain_name (0.5.20190701)
57 | unf (>= 0.0.5, < 1.0.0)
58 | dotenv (2.7.5)
59 | emoji_regex (1.0.1)
60 | escape (0.0.4)
61 | excon (0.71.0)
62 | faraday (0.15.4)
63 | multipart-post (>= 1.2, < 3)
64 | faraday-cookie_jar (0.0.6)
65 | faraday (>= 0.7.4)
66 | http-cookie (~> 1.0.0)
67 | faraday-http-cache (2.0.0)
68 | faraday (~> 0.8)
69 | faraday_middleware (0.13.1)
70 | faraday (>= 0.7.4, < 1.0)
71 | fastimage (2.1.5)
72 | fastlane (2.129.0)
73 | CFPropertyList (>= 2.3, < 4.0.0)
74 | addressable (>= 2.3, < 3.0.0)
75 | babosa (>= 1.0.2, < 2.0.0)
76 | bundler (>= 1.12.0, < 3.0.0)
77 | colored
78 | commander-fastlane (>= 4.4.6, < 5.0.0)
79 | dotenv (>= 2.1.1, < 3.0.0)
80 | emoji_regex (>= 0.1, < 2.0)
81 | excon (>= 0.45.0, < 1.0.0)
82 | faraday (~> 0.9)
83 | faraday-cookie_jar (~> 0.0.6)
84 | faraday_middleware (~> 0.9)
85 | fastimage (>= 2.1.0, < 3.0.0)
86 | gh_inspector (>= 1.1.2, < 2.0.0)
87 | google-api-client (>= 0.21.2, < 0.24.0)
88 | google-cloud-storage (>= 1.15.0, < 2.0.0)
89 | highline (>= 1.7.2, < 2.0.0)
90 | json (< 3.0.0)
91 | jwt (~> 2.1.0)
92 | mini_magick (>= 4.9.4, < 5.0.0)
93 | multi_xml (~> 0.5)
94 | multipart-post (~> 2.0.0)
95 | plist (>= 3.1.0, < 4.0.0)
96 | public_suffix (~> 2.0.0)
97 | rubyzip (>= 1.2.2, < 2.0.0)
98 | security (= 0.1.3)
99 | simctl (~> 1.6.3)
100 | slack-notifier (>= 2.0.0, < 3.0.0)
101 | terminal-notifier (>= 2.0.0, < 3.0.0)
102 | terminal-table (>= 1.4.5, < 2.0.0)
103 | tty-screen (>= 0.6.3, < 1.0.0)
104 | tty-spinner (>= 0.8.0, < 1.0.0)
105 | word_wrap (~> 1.0.0)
106 | xcodeproj (>= 1.8.1, < 2.0.0)
107 | xcpretty (~> 0.3.0)
108 | xcpretty-travis-formatter (>= 0.0.3)
109 | fourflusher (2.3.1)
110 | fuzzy_match (2.0.4)
111 | gh_inspector (1.1.3)
112 | github_changelog_generator (1.14.3)
113 | activesupport
114 | faraday-http-cache
115 | multi_json
116 | octokit (~> 4.6)
117 | rainbow (>= 2.1)
118 | rake (>= 10.0)
119 | retriable (~> 2.1)
120 | google-api-client (0.23.9)
121 | addressable (~> 2.5, >= 2.5.1)
122 | googleauth (>= 0.5, < 0.7.0)
123 | httpclient (>= 2.8.1, < 3.0)
124 | mime-types (~> 3.0)
125 | representable (~> 3.0)
126 | retriable (>= 2.0, < 4.0)
127 | signet (~> 0.9)
128 | google-cloud-core (1.3.0)
129 | google-cloud-env (~> 1.0)
130 | google-cloud-env (1.2.0)
131 | faraday (~> 0.11)
132 | google-cloud-storage (1.16.0)
133 | digest-crc (~> 0.4)
134 | google-api-client (~> 0.23)
135 | google-cloud-core (~> 1.2)
136 | googleauth (>= 0.6.2, < 0.10.0)
137 | googleauth (0.6.7)
138 | faraday (~> 0.12)
139 | jwt (>= 1.4, < 3.0)
140 | memoist (~> 0.16)
141 | multi_json (~> 1.11)
142 | os (>= 0.9, < 2.0)
143 | signet (~> 0.7)
144 | highline (1.7.10)
145 | http-cookie (1.0.3)
146 | domain_name (~> 0.5)
147 | httpclient (2.8.3)
148 | i18n (0.9.5)
149 | concurrent-ruby (~> 1.0)
150 | json (2.3.1)
151 | jwt (2.1.0)
152 | memoist (0.16.0)
153 | mime-types (3.2.2)
154 | mime-types-data (~> 3.2015)
155 | mime-types-data (3.2019.0331)
156 | mini_magick (4.9.5)
157 | minitest (5.11.3)
158 | molinillo (0.6.6)
159 | multi_json (1.13.1)
160 | multi_xml (0.6.0)
161 | multipart-post (2.0.0)
162 | nanaimo (0.2.6)
163 | nap (1.1.0)
164 | naturally (2.2.0)
165 | netrc (0.11.0)
166 | octokit (4.14.0)
167 | sawyer (~> 0.8.0, >= 0.5.3)
168 | os (1.0.1)
169 | plist (3.5.0)
170 | public_suffix (2.0.5)
171 | rainbow (3.0.0)
172 | rake (12.3.3)
173 | representable (3.0.4)
174 | declarative (< 0.1.0)
175 | declarative-option (< 0.2.0)
176 | uber (< 0.2.0)
177 | retriable (2.1.0)
178 | rouge (2.0.7)
179 | ruby-macho (1.4.0)
180 | rubyzip (1.3.0)
181 | sawyer (0.8.2)
182 | addressable (>= 2.3.5)
183 | faraday (> 0.8, < 2.0)
184 | security (0.1.3)
185 | signet (0.11.0)
186 | addressable (~> 2.3)
187 | faraday (~> 0.9)
188 | jwt (>= 1.5, < 3.0)
189 | multi_json (~> 1.10)
190 | simctl (1.6.5)
191 | CFPropertyList
192 | naturally
193 | slack-notifier (2.3.2)
194 | terminal-notifier (2.0.0)
195 | terminal-table (1.8.0)
196 | unicode-display_width (~> 1.1, >= 1.1.1)
197 | thread_safe (0.3.6)
198 | tty-cursor (0.7.0)
199 | tty-screen (0.7.0)
200 | tty-spinner (0.9.1)
201 | tty-cursor (~> 0.7)
202 | tzinfo (1.2.5)
203 | thread_safe (~> 0.1)
204 | uber (0.1.0)
205 | unf (0.1.4)
206 | unf_ext
207 | unf_ext (0.0.7.6)
208 | unicode-display_width (1.6.0)
209 | word_wrap (1.0.0)
210 | xcodeproj (1.12.0)
211 | CFPropertyList (>= 2.3.3, < 4.0)
212 | atomos (~> 0.1.3)
213 | claide (>= 1.0.2, < 2.0)
214 | colored2 (~> 3.1)
215 | nanaimo (~> 0.2.6)
216 | xcpretty (0.3.0)
217 | rouge (~> 2.0.7)
218 | xcpretty-travis-formatter (1.0.0)
219 | xcpretty (~> 0.2, >= 0.0.7)
220 |
221 | PLATFORMS
222 | ruby
223 |
224 | DEPENDENCIES
225 | cocoapods
226 | fastlane
227 | github_changelog_generator
228 |
229 | BUNDLED WITH
230 | 1.16.6
231 |
--------------------------------------------------------------------------------
/StoryboardKit/ApplicationInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ApplicationInfo.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 5/3/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | * Contains information global to your application
13 | */
14 | public class ApplicationInfo: NSObject {
15 | /// All View Controller Class Infos in your application
16 | public private(set) var viewControllerClasses = [ViewControllerClassInfo]()
17 |
18 | /**
19 | Add a View Controller Class Info
20 |
21 | - parameter viewControllerClass: View Controller Class Info to add
22 | */
23 | func add(viewControllerClass viewControllerClass : ViewControllerClassInfo) {
24 | // TODO: validates that this isn't a dup
25 | self.viewControllerClasses.append(viewControllerClass)
26 | }
27 |
28 | /**
29 | Retrieve a View Controller Class Info by class name
30 |
31 | - parameter className: Name of the class you wish to retrieve
32 |
33 | - returns: If found a reference to the View Controller Class Info you wished to retrieve, otherwise nil
34 | */
35 | public func viewControllerClassWithClassName(className : String) -> ViewControllerClassInfo? {
36 | return classWithClassName(className, objects: self.viewControllerClasses)
37 | }
38 |
39 | /// All View Controller Instance Infos in your application
40 | public private(set) var viewControllerInstances = [ViewControllerInstanceInfo]()
41 |
42 | /**
43 | Add a View Controller Instance Info
44 |
45 | - parameter viewControllerInstance: View Controller Instance Info to add
46 | */
47 | func add(viewControllerInstance viewControllerInstance : ViewControllerInstanceInfo) {
48 | // TODO: validates that this isn't a dup
49 | self.viewControllerInstances.append(viewControllerInstance)
50 | }
51 |
52 | /**
53 | Retrieve a View Controller Instance Info by Storyboard id
54 |
55 | - parameter id: Storyboard id of the instance you wish to retrieve (not to be confused with IB assigned identifier)
56 |
57 | - returns: If found a reference to the View Controller Instance Info you wished to retrieve, otherwise nil
58 | */
59 | public func viewControllerInstanceWithId(id : String) -> ViewControllerInstanceInfo? {
60 | return firstObjectWithId(id, objects: self.viewControllerInstances)
61 | }
62 |
63 | /**
64 | Retrieve a View Controller Instance Info by Storyboard Identifier
65 |
66 | - parameter id: Storyboard Identifier of the instance you wish to retrieve
67 |
68 | - returns: If found a reference to the View Controller Instance Info you wished to retrieve, otherwise nil
69 | */
70 | public func viewControllerInstanceWithStoryboardIdentifier(identifier : String) -> ViewControllerInstanceInfo? {
71 | return self.viewControllerInstances.filter( { $0.storyboardIdentifier == identifier} ).first
72 | }
73 |
74 | /// All Navigation Controller Instance Infos in your application
75 | public private(set) var navigationControllerInstances = [NavigationControllerInstanceInfo]()
76 |
77 | /**
78 | Add a Navigation Controller Instance Info to your application
79 |
80 | - parameter navigationControllerInstance: Navigation Controller Instance Info to add
81 | */
82 | func add(navigationControllerInstance navigationControllerInstance : NavigationControllerInstanceInfo) {
83 | // TODO: validates that this isn't a dup
84 | self.navigationControllerInstances.append(navigationControllerInstance)
85 | }
86 |
87 | /**
88 | Retrieve a Navigation Controller Instance Info by Storyboard id
89 |
90 | - parameter id: Storyboard id of the instance you wish to retrieve (not to be confused with IB assigned identifier)
91 |
92 | - returns: If found a reference to the Navigation Controller Instance Info you wished to retrieve, otherwise nil
93 | */
94 | public func navigationControllerInstanceWithId(id : String) -> NavigationControllerInstanceInfo? {
95 | return firstObjectWithId(id, objects: self.navigationControllerInstances)
96 | }
97 |
98 | /**
99 | Retrieve a Navigation Controller Instance Info by Storyboard Identifier
100 |
101 | - parameter id: Storyboard Identifier of the instance you wish to retrieve
102 |
103 | - returns: If found a reference to the Navigation Controller Instance Info you wished to retrieve, otherwise nil
104 | */
105 | public func navigationControllerInstanceWithStoryboardIdentifier(identifier : String) -> NavigationControllerInstanceInfo? {
106 | return self.navigationControllerInstances.filter( { $0.storyboardIdentifier == identifier} ).first
107 | }
108 |
109 | /// All Tab Bar Controller Instance Infos in your application
110 | public private(set) var tabBarControllerInstances = [TabBarControllerInstanceInfo]()
111 |
112 | /**
113 | Add a Tab Bar Controller Instance Info to your application
114 |
115 | - parameter tabBarControllerInstance: Tab Bar Controller Instance Info to add
116 | */
117 | func add(tabBarControllerInstance tabBarControllerInstance : TabBarControllerInstanceInfo) {
118 | // TODO: validates that this isn't a dup
119 | self.tabBarControllerInstances.append(tabBarControllerInstance)
120 | }
121 |
122 | /**
123 | Retrieve a Tab Bar Controller Instance Info by Storyboard id
124 |
125 | - parameter id: Storyboard id of the instance you wish to retrieve (not to be confused with IB assigned identifier)
126 |
127 | - returns: If found a reference to the Tab Bar Controller Instance Info you wished to retrieve, otherwise nil
128 | */
129 | public func tabBarControllerInstanceWithId(id : String) -> TabBarControllerInstanceInfo? {
130 | return firstObjectWithId(id, objects: self.tabBarControllerInstances)
131 | }
132 |
133 | /**
134 | Retrieve a Tab Bar Controller Instance Info by Storyboard Identifier
135 |
136 | - parameter id: Storyboard Identifier of the instance you wish to retrieve
137 |
138 | - returns: If found a reference to the Tab Bar Controller Instance Info you wished to retrieve, otherwise nil
139 | */
140 | public func tabBarControllerInstanceWithStoryboardIdentifier(identifier : String) -> TabBarControllerInstanceInfo? {
141 | return self.tabBarControllerInstances.filter( { $0.storyboardIdentifier == identifier} ).first
142 | }
143 |
144 | /// All Segue Class Infos in your application
145 | public private(set) var segueClasses = [SegueClassInfo]()
146 |
147 | /**
148 | Add a Segue Class Info to your application
149 |
150 | - parameter segueClass: Segue Class Info to add
151 | */
152 | func add(segueClass segueClass : SegueClassInfo) {
153 | // TODO: validates that this isn't a dup
154 | self.segueClasses.append(segueClass)
155 | }
156 |
157 | /**
158 | Retrieve a Segue Class Info by class name
159 |
160 | - parameter className: Name of the class you wish to retrieve
161 |
162 | - returns: If found a reference to the Segue Class Info you wished to retrieve, otherwise nil
163 | */
164 | public func segueClassWithClassName(className : String) -> SegueClassInfo? {
165 | return classWithClassName(className, objects: self.segueClasses)
166 | }
167 |
168 | // TODO: store SegueInstances
169 |
170 | /// All View Class Infos in your application
171 | public private(set) var viewClasses = [ViewClassInfo]()
172 |
173 | /**
174 | Add a View Class Info to your application
175 |
176 | - parameter viewClass: View Class Info to add
177 | */
178 | func add(viewClass viewClass : ViewClassInfo) {
179 | // TODO: validates that this isn't a dup
180 | self.viewClasses.append(viewClass)
181 | }
182 |
183 | /**
184 | Retrieve a View Class Info by class name
185 |
186 | - parameter className: Name of the class you wish to retrieve
187 |
188 | - returns: If found a reference to the View Class Info you wished to retrieve, otherwise nil
189 | */
190 | public func viewClassWithClassName(className : String) -> ViewClassInfo? {
191 | return classWithClassName(className, objects: self.viewClasses)
192 | }
193 |
194 | /**
195 | Retrieve a View Instance Info by id
196 |
197 | - parameter id: id of the instance you wish to retrieve
198 |
199 | - returns: If found a reference to the View Instance Info you wished to retrieve, otherwise nil
200 | */
201 | public func viewInstanceWithId(id : String) -> ViewInstanceInfo? {
202 | var result : ViewInstanceInfo?
203 |
204 | for viewClass in self.viewClasses
205 | {
206 | for viewInstanceWeakWrapper in viewClass.instanceInfos
207 | {
208 | if let viewInstance = viewInstanceWeakWrapper.value
209 | {
210 | if viewInstance.id == id
211 | {
212 | result = viewInstance
213 | break
214 | }
215 | }
216 | }
217 |
218 | if result != nil
219 | {
220 | break
221 | }
222 | }
223 |
224 | return result
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileVersionedParsers/3.0/StoryboardFile3_0Parser_ViewControllers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFile3_0Parser_ViewControllers.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/30/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | internal extension StoryboardFile3_0Parser {
14 | // MARK: View Controllers
15 |
16 | internal class func useClass(element : XMLElement, classInfo : ViewControllerClassInfo.Type) -> String
17 | {
18 | var result : String
19 | if let customClass = element.allAttributes["customClass"]?.text
20 | {
21 | result = customClass
22 | } else
23 | {
24 | result = classInfo.defaultClass
25 | }
26 | return result
27 | }
28 |
29 | internal func findOrCreateViewControllerClassInfo(useClass : String, classInfo : ViewControllerClassInfo.Type) -> ViewControllerClassInfo
30 | {
31 | let result : ViewControllerClassInfo
32 |
33 | if let controllerClassInfo = self.applicationInfo.viewControllerClassWithClassName(useClass) // TODO: as? classInfo
34 | {
35 | result = controllerClassInfo
36 | } else
37 | {
38 | result = classInfo.init(className: useClass)
39 | self.applicationInfo.add(viewControllerClass: result)
40 | }
41 |
42 | return result
43 | }
44 |
45 | internal func parseViewController(viewController : XMLIndexer, sceneInfo : StoryboardInstanceInfo.SceneInfo) {
46 | if let element = viewController.element,
47 | let id = element.allAttributes["id"]?.text
48 | {
49 | let useClass = StoryboardFile3_0Parser.useClass(element, classInfo: ViewControllerClassInfo.self)
50 |
51 | var viewControllerClassInfo = self.applicationInfo.viewControllerClassWithClassName(useClass)
52 | if viewControllerClassInfo == nil
53 | {
54 | viewControllerClassInfo = ViewControllerClassInfo(className: useClass)
55 | self.applicationInfo.add(viewControllerClass: viewControllerClassInfo!)
56 | }
57 |
58 | let storyboardIdentifier = element.allAttributes["storyboardIdentifier"]?.text
59 |
60 | var view : ViewInstanceInfo? // Should be using view.key attribute?
61 |
62 | // This is garbage, find a cleaner way
63 | if let possibleView = self.createView(viewController["view"])
64 | {
65 | view = possibleView
66 | } else if let possibleTableView = self.createTableView(viewController["tableView"])
67 | {
68 | view = possibleTableView
69 | } else if let possibleCollectionView = self.createCollectionView(viewController["collectionView"])
70 | {
71 | view = possibleCollectionView
72 | }
73 |
74 | let viewControllerInstanceInfo = ViewControllerInstanceInfo(classInfo: viewControllerClassInfo!, id: id, storyboardIdentifier: storyboardIdentifier, view: view)
75 |
76 | sceneInfo.controller = viewControllerInstanceInfo
77 | self.applicationInfo.add(viewControllerInstance: viewControllerInstanceInfo)
78 |
79 | self.parseLayoutGuides(viewController["layoutGuides"], source: viewControllerInstanceInfo)
80 |
81 | let navigationItem = viewController["navigationItem"]
82 | if navigationItem.element != nil
83 | {
84 | self.parseNavigationItem(navigationItem, source: viewControllerInstanceInfo)
85 | }
86 |
87 | self.parseConnections(viewController["connections"], source: viewControllerInstanceInfo)
88 | }
89 | }
90 |
91 | // MARK: Navigation Controller
92 |
93 | internal func parseNavigationController(navigationController : XMLIndexer, sceneInfo : StoryboardInstanceInfo.SceneInfo) {
94 | if let element = navigationController.element, let id = element.allAttributes["id"]?.text
95 | {
96 | let useClass = StoryboardFile3_0Parser.useClass(element, classInfo: NavigationControllerClassInfo.self)
97 |
98 | // TODO: restrict to NavControllerClasses
99 | var navigationControllerClassInfo = self.applicationInfo.viewControllerClassWithClassName(useClass) as? NavigationControllerClassInfo
100 | if navigationControllerClassInfo == nil
101 | {
102 | navigationControllerClassInfo = NavigationControllerClassInfo(className: useClass)
103 | self.applicationInfo.add(viewControllerClass: navigationControllerClassInfo!)
104 | }
105 |
106 | let storyboardIdentifier = element.allAttributes["storyboardIdentifier"]?.text
107 | let sceneMemberId = element.allAttributes["sceneMemberID"]?.text
108 |
109 | let navigationControllerInstanceInfo = NavigationControllerInstanceInfo(classInfo: navigationControllerClassInfo!, id: id, storyboardIdentifier: storyboardIdentifier, sceneMemberId: sceneMemberId)
110 |
111 | sceneInfo.controller = navigationControllerInstanceInfo
112 | self.applicationInfo.add(navigationControllerInstance: navigationControllerInstanceInfo)
113 |
114 | /* var navigationBar = viewController["navigationBar"] //TODO: can this be optional?
115 | if navigationBar.element != nil
116 | {
117 | self.parseNavigationBar(navigationBar, source: navigationControllerInstanceInfo)
118 | }
119 | */
120 | self.parseConnections(navigationController["connections"], source: navigationControllerInstanceInfo)
121 | }
122 | }
123 |
124 | // MARK: Tab Bar Controller
125 |
126 | internal func parseTabBarController(viewController : XMLIndexer, sceneInfo : StoryboardInstanceInfo.SceneInfo) {
127 | if let element = viewController.element,
128 | let id = element.allAttributes["id"]?.text
129 | {
130 | let useClass = StoryboardFile3_0Parser.useClass(element, classInfo: TabBarControllerClassInfo.self)
131 |
132 | let classInfo = self.findOrCreateViewControllerClassInfo(useClass, classInfo: TabBarControllerClassInfo.self)
133 |
134 | let storyboardIdentifier = element.allAttributes["storyboardIdentifier"]?.text
135 |
136 | let view = self.createView(viewController["view"]) // Should be using view.key attribute?
137 |
138 | let instanceInfo = TabBarControllerInstanceInfo(classInfo: classInfo, id: id, storyboardIdentifier: storyboardIdentifier, view: view)
139 |
140 | sceneInfo.controller = instanceInfo
141 | self.applicationInfo.add(tabBarControllerInstance: instanceInfo)
142 |
143 | self.parseLayoutGuides(viewController["layoutGuides"], source: instanceInfo)
144 |
145 | let navigationItem = viewController["navigationItem"]
146 | if navigationItem.element != nil
147 | {
148 | self.parseNavigationItem(navigationItem, source: instanceInfo)
149 | }
150 |
151 | self.parseConnections(viewController["connections"], source: instanceInfo)
152 | }
153 | }
154 |
155 | // MARK: Layout Guides
156 |
157 | internal func parseLayoutGuides(layoutGuides : XMLIndexer, source : ViewControllerInstanceInfo) {
158 | for layoutGuide in layoutGuides.children
159 | {
160 | self.parseLayoutGuide(layoutGuide, source: source)
161 | }
162 | }
163 |
164 | internal func parseLayoutGuide(layoutGuide : XMLIndexer, source : ViewControllerInstanceInfo) {
165 |
166 | if let element = layoutGuide.element,
167 | let id = element.allAttributes["id"]?.text,
168 | let type = element.allAttributes["type"]?.text
169 | {
170 | let layoutGuide = ViewControllerLayoutGuideInstanceInfo(id: id, type: type )
171 | source.add(layoutGuide: layoutGuide)
172 | } else
173 | {
174 | self.Log("Unable to create View Controller Layout Guide Instance Info from \(layoutGuide)")
175 | }
176 | }
177 |
178 | // MARK: Navigation Item
179 |
180 | internal func parseNavigationItem(navigationItem : XMLIndexer, source : ViewControllerInstanceInfo) {
181 |
182 | switch navigationItem
183 | {
184 | case .Element(let element):
185 | if let id = element.allAttributes["id"]?.text,
186 | let navigationItemKey = element.allAttributes["key"]?.text,
187 | let title = element.allAttributes["title"]?.text
188 | {
189 | let navigationItemInstance = NavigationItemInstanceInfo(id: id, navigationItemKey: navigationItemKey, title: title)
190 | source.add(navigationItem: navigationItemInstance)
191 | } else
192 | {
193 | self.Log("Unable to create Navigation Item Instance Info from \(navigationItem)")
194 | }
195 | break
196 | case .XMLError(let error):
197 | self.Log("Unable to create Navigation Item Instance Info from \(navigationItem): \(error)")
198 | break
199 | default:
200 | self.Log("Unable to create Navigation Item Instance Info from \(navigationItem), unhandled element \(navigationItem.element)")
201 | }
202 | }
203 |
204 | // MARK: Connections
205 |
206 | internal func parseConnection(connection : XMLIndexer, source : ViewControllerInstanceInfo) {
207 | if let element = connection.element
208 | {
209 | if element.name == "segue"
210 | {
211 | if let segueParseInfo = self.createConnectionParseInfo(connection, source: source )
212 | {
213 | self.parsedSegues.append(segueParseInfo)
214 | }
215 | } else
216 | {
217 | self.Log("Skipping unsupported connection type \(element.name)")
218 | }
219 | }
220 | }
221 |
222 | internal func parseConnections(connections : XMLIndexer, source : ViewControllerInstanceInfo) {
223 | for connection in connections.children
224 | {
225 | self.parseConnection(connection, source: source)
226 | }
227 | }
228 | }
--------------------------------------------------------------------------------
/Cocoapod/StoryboardKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3C1245831C209F5400525217 /* ApplicationInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C12455C1C209E7E00525217 /* ApplicationInfoTests.swift */; };
11 | 3C1245841C209F5400525217 /* ClassInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C12455D1C209E7E00525217 /* ClassInfoTests.swift */; };
12 | 3C1245861C209F5400525217 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3C12455F1C209E7E00525217 /* Images.xcassets */; };
13 | 3C1245881C209F5400525217 /* StoryboardFileParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1245611C209E7E00525217 /* StoryboardFileParserTests.swift */; };
14 | 3C1245891C209F5400525217 /* StoryboardInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1245621C209E7E00525217 /* StoryboardInfoTests.swift */; };
15 | 3C12458A1C209F5400525217 /* StoryboardInstanceInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1245631C209E7E00525217 /* StoryboardInstanceInfoTests.swift */; };
16 | 3C12458C1C209F5400525217 /* TableViewInstanceInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1245651C209E7E00525217 /* TableViewInstanceInfoTests.swift */; };
17 | 3C12458D1C209F5400525217 /* ViewInstanceInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1245661C209E7E00525217 /* ViewInstanceInfoTests.swift */; };
18 | 3C12458F1C20A07700525217 /* StoryboardKit.storyboard in Copy iOS Storyboaard */ = {isa = PBXBuildFile; fileRef = 3C1245641C209E7E00525217 /* StoryboardKit.storyboard */; };
19 | E40A379BD928D05C4C108DB2 /* Pods_CocoapodTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D5557C7BDAE283B154FD653 /* Pods_CocoapodTests.framework */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXCopyFilesBuildPhase section */
23 | 3C12458E1C20A06200525217 /* Copy iOS Storyboaard */ = {
24 | isa = PBXCopyFilesBuildPhase;
25 | buildActionMask = 2147483647;
26 | dstPath = "";
27 | dstSubfolderSpec = 7;
28 | files = (
29 | 3C12458F1C20A07700525217 /* StoryboardKit.storyboard in Copy iOS Storyboaard */,
30 | );
31 | name = "Copy iOS Storyboaard";
32 | runOnlyForDeploymentPostprocessing = 0;
33 | };
34 | /* End PBXCopyFilesBuildPhase section */
35 |
36 | /* Begin PBXFileReference section */
37 | 3C12455C1C209E7E00525217 /* ApplicationInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationInfoTests.swift; sourceTree = ""; };
38 | 3C12455D1C209E7E00525217 /* ClassInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClassInfoTests.swift; sourceTree = ""; };
39 | 3C12455F1C209E7E00525217 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
40 | 3C1245601C209E7E00525217 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | 3C1245611C209E7E00525217 /* StoryboardFileParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardFileParserTests.swift; sourceTree = ""; };
42 | 3C1245621C209E7E00525217 /* StoryboardInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardInfoTests.swift; sourceTree = ""; };
43 | 3C1245631C209E7E00525217 /* StoryboardInstanceInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardInstanceInfoTests.swift; sourceTree = ""; };
44 | 3C1245641C209E7E00525217 /* StoryboardKit.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = StoryboardKit.storyboard; sourceTree = ""; };
45 | 3C1245651C209E7E00525217 /* TableViewInstanceInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewInstanceInfoTests.swift; sourceTree = ""; };
46 | 3C1245661C209E7E00525217 /* ViewInstanceInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewInstanceInfoTests.swift; sourceTree = ""; };
47 | 3C1245731C209E9D00525217 /* StoryboardKit.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StoryboardKit.podspec; path = ../StoryboardKit.podspec; sourceTree = SOURCE_ROOT; };
48 | 3C12457A1C209F1F00525217 /* CocoapodTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CocoapodTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
49 | 7360C8C399AA4BCDA1485EA6 /* Pods-CocoapodTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CocoapodTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CocoapodTests/Pods-CocoapodTests.release.xcconfig"; sourceTree = ""; };
50 | 7D5557C7BDAE283B154FD653 /* Pods_CocoapodTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CocoapodTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
51 | C57DC03E4498CE1BFA77FA1E /* Pods-CocoapodTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CocoapodTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CocoapodTests/Pods-CocoapodTests.debug.xcconfig"; sourceTree = ""; };
52 | /* End PBXFileReference section */
53 |
54 | /* Begin PBXFrameworksBuildPhase section */
55 | 3C1245771C209F1F00525217 /* Frameworks */ = {
56 | isa = PBXFrameworksBuildPhase;
57 | buildActionMask = 2147483647;
58 | files = (
59 | E40A379BD928D05C4C108DB2 /* Pods_CocoapodTests.framework in Frameworks */,
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | /* End PBXFrameworksBuildPhase section */
64 |
65 | /* Begin PBXGroup section */
66 | 09EAA0F2DD47C0B231DA86BB /* Frameworks */ = {
67 | isa = PBXGroup;
68 | children = (
69 | 7D5557C7BDAE283B154FD653 /* Pods_CocoapodTests.framework */,
70 | );
71 | name = Frameworks;
72 | sourceTree = "";
73 | };
74 | 3C12453A1C209E1E00525217 = {
75 | isa = PBXGroup;
76 | children = (
77 | 3C12455B1C209E7E00525217 /* StoryboardKitTests */,
78 | 3C1245821C209F4600525217 /* Supporting Files */,
79 | 3C1245451C209E1E00525217 /* Products */,
80 | F09A357FF4D3F33BE53EAE35 /* Pods */,
81 | 09EAA0F2DD47C0B231DA86BB /* Frameworks */,
82 | );
83 | sourceTree = "";
84 | };
85 | 3C1245451C209E1E00525217 /* Products */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 3C12457A1C209F1F00525217 /* CocoapodTests.xctest */,
89 | );
90 | name = Products;
91 | sourceTree = "";
92 | };
93 | 3C12455B1C209E7E00525217 /* StoryboardKitTests */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 3C12455C1C209E7E00525217 /* ApplicationInfoTests.swift */,
97 | 3C12455D1C209E7E00525217 /* ClassInfoTests.swift */,
98 | 3C12455F1C209E7E00525217 /* Images.xcassets */,
99 | 3C1245601C209E7E00525217 /* Info.plist */,
100 | 3C1245611C209E7E00525217 /* StoryboardFileParserTests.swift */,
101 | 3C1245621C209E7E00525217 /* StoryboardInfoTests.swift */,
102 | 3C1245631C209E7E00525217 /* StoryboardInstanceInfoTests.swift */,
103 | 3C1245641C209E7E00525217 /* StoryboardKit.storyboard */,
104 | 3C1245651C209E7E00525217 /* TableViewInstanceInfoTests.swift */,
105 | 3C1245661C209E7E00525217 /* ViewInstanceInfoTests.swift */,
106 | );
107 | name = StoryboardKitTests;
108 | path = ../StoryboardKitTests;
109 | sourceTree = "";
110 | };
111 | 3C1245821C209F4600525217 /* Supporting Files */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 3C1245731C209E9D00525217 /* StoryboardKit.podspec */,
115 | );
116 | name = "Supporting Files";
117 | sourceTree = "";
118 | };
119 | F09A357FF4D3F33BE53EAE35 /* Pods */ = {
120 | isa = PBXGroup;
121 | children = (
122 | C57DC03E4498CE1BFA77FA1E /* Pods-CocoapodTests.debug.xcconfig */,
123 | 7360C8C399AA4BCDA1485EA6 /* Pods-CocoapodTests.release.xcconfig */,
124 | );
125 | name = Pods;
126 | sourceTree = "";
127 | };
128 | /* End PBXGroup section */
129 |
130 | /* Begin PBXNativeTarget section */
131 | 3C1245791C209F1F00525217 /* CocoapodTests */ = {
132 | isa = PBXNativeTarget;
133 | buildConfigurationList = 3C12457F1C209F1F00525217 /* Build configuration list for PBXNativeTarget "CocoapodTests" */;
134 | buildPhases = (
135 | 1B05B9F136D1834A82215664 /* [CP] Check Pods Manifest.lock */,
136 | 3C1245761C209F1F00525217 /* Sources */,
137 | 3C1245771C209F1F00525217 /* Frameworks */,
138 | 3C1245781C209F1F00525217 /* Resources */,
139 | 3C12458E1C20A06200525217 /* Copy iOS Storyboaard */,
140 | 94CEB39D5BE692C2A16290F5 /* [CP] Embed Pods Frameworks */,
141 | 5F4B0CC39C79F9287BE27420 /* [CP] Copy Pods Resources */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = CocoapodTests;
148 | productName = CocoapodTests;
149 | productReference = 3C12457A1C209F1F00525217 /* CocoapodTests.xctest */;
150 | productType = "com.apple.product-type.bundle.unit-test";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 3C12453B1C209E1E00525217 /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastSwiftUpdateCheck = 0720;
159 | LastUpgradeCheck = 0730;
160 | ORGANIZATIONNAME = Adorkable;
161 | TargetAttributes = {
162 | 3C1245791C209F1F00525217 = {
163 | CreatedOnToolsVersion = 7.2;
164 | };
165 | };
166 | };
167 | buildConfigurationList = 3C12453E1C209E1E00525217 /* Build configuration list for PBXProject "StoryboardKit" */;
168 | compatibilityVersion = "Xcode 3.2";
169 | developmentRegion = English;
170 | hasScannedForEncodings = 0;
171 | knownRegions = (
172 | en,
173 | );
174 | mainGroup = 3C12453A1C209E1E00525217;
175 | productRefGroup = 3C1245451C209E1E00525217 /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 3C1245791C209F1F00525217 /* CocoapodTests */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | 3C1245781C209F1F00525217 /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 3C1245861C209F5400525217 /* Images.xcassets in Resources */,
190 | );
191 | runOnlyForDeploymentPostprocessing = 0;
192 | };
193 | /* End PBXResourcesBuildPhase section */
194 |
195 | /* Begin PBXShellScriptBuildPhase section */
196 | 1B05B9F136D1834A82215664 /* [CP] Check Pods Manifest.lock */ = {
197 | isa = PBXShellScriptBuildPhase;
198 | buildActionMask = 2147483647;
199 | files = (
200 | );
201 | inputPaths = (
202 | );
203 | name = "[CP] Check Pods Manifest.lock";
204 | outputPaths = (
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | shellPath = /bin/sh;
208 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
209 | showEnvVarsInLog = 0;
210 | };
211 | 5F4B0CC39C79F9287BE27420 /* [CP] Copy Pods Resources */ = {
212 | isa = PBXShellScriptBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | );
216 | inputPaths = (
217 | );
218 | name = "[CP] Copy Pods Resources";
219 | outputPaths = (
220 | );
221 | runOnlyForDeploymentPostprocessing = 0;
222 | shellPath = /bin/sh;
223 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CocoapodTests/Pods-CocoapodTests-resources.sh\"\n";
224 | showEnvVarsInLog = 0;
225 | };
226 | 94CEB39D5BE692C2A16290F5 /* [CP] Embed Pods Frameworks */ = {
227 | isa = PBXShellScriptBuildPhase;
228 | buildActionMask = 2147483647;
229 | files = (
230 | );
231 | inputPaths = (
232 | );
233 | name = "[CP] Embed Pods Frameworks";
234 | outputPaths = (
235 | );
236 | runOnlyForDeploymentPostprocessing = 0;
237 | shellPath = /bin/sh;
238 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CocoapodTests/Pods-CocoapodTests-frameworks.sh\"\n";
239 | showEnvVarsInLog = 0;
240 | };
241 | /* End PBXShellScriptBuildPhase section */
242 |
243 | /* Begin PBXSourcesBuildPhase section */
244 | 3C1245761C209F1F00525217 /* Sources */ = {
245 | isa = PBXSourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | 3C1245841C209F5400525217 /* ClassInfoTests.swift in Sources */,
249 | 3C1245831C209F5400525217 /* ApplicationInfoTests.swift in Sources */,
250 | 3C1245881C209F5400525217 /* StoryboardFileParserTests.swift in Sources */,
251 | 3C1245891C209F5400525217 /* StoryboardInfoTests.swift in Sources */,
252 | 3C12458D1C209F5400525217 /* ViewInstanceInfoTests.swift in Sources */,
253 | 3C12458C1C209F5400525217 /* TableViewInstanceInfoTests.swift in Sources */,
254 | 3C12458A1C209F5400525217 /* StoryboardInstanceInfoTests.swift in Sources */,
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | /* End PBXSourcesBuildPhase section */
259 |
260 | /* Begin XCBuildConfiguration section */
261 | 3C12454A1C209E1E00525217 /* Debug */ = {
262 | isa = XCBuildConfiguration;
263 | buildSettings = {
264 | ALWAYS_SEARCH_USER_PATHS = NO;
265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
266 | CLANG_CXX_LIBRARY = "libc++";
267 | CLANG_ENABLE_MODULES = YES;
268 | CLANG_ENABLE_OBJC_ARC = YES;
269 | CLANG_WARN_BOOL_CONVERSION = YES;
270 | CLANG_WARN_CONSTANT_CONVERSION = YES;
271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
272 | CLANG_WARN_EMPTY_BODY = YES;
273 | CLANG_WARN_ENUM_CONVERSION = YES;
274 | CLANG_WARN_INT_CONVERSION = YES;
275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
276 | CLANG_WARN_UNREACHABLE_CODE = YES;
277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
278 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
279 | COPY_PHASE_STRIP = NO;
280 | CURRENT_PROJECT_VERSION = 1;
281 | DEBUG_INFORMATION_FORMAT = dwarf;
282 | ENABLE_STRICT_OBJC_MSGSEND = YES;
283 | ENABLE_TESTABILITY = YES;
284 | GCC_C_LANGUAGE_STANDARD = gnu99;
285 | GCC_DYNAMIC_NO_PIC = NO;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_OPTIMIZATION_LEVEL = 0;
288 | GCC_PREPROCESSOR_DEFINITIONS = (
289 | "DEBUG=1",
290 | "$(inherited)",
291 | );
292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
294 | GCC_WARN_UNDECLARED_SELECTOR = YES;
295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
296 | GCC_WARN_UNUSED_FUNCTION = YES;
297 | GCC_WARN_UNUSED_VARIABLE = YES;
298 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
299 | MTL_ENABLE_DEBUG_INFO = YES;
300 | ONLY_ACTIVE_ARCH = YES;
301 | SDKROOT = iphoneos;
302 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
303 | TARGETED_DEVICE_FAMILY = "1,2";
304 | VERSIONING_SYSTEM = "apple-generic";
305 | VERSION_INFO_PREFIX = "";
306 | };
307 | name = Debug;
308 | };
309 | 3C12454B1C209E1E00525217 /* Release */ = {
310 | isa = XCBuildConfiguration;
311 | buildSettings = {
312 | ALWAYS_SEARCH_USER_PATHS = NO;
313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
314 | CLANG_CXX_LIBRARY = "libc++";
315 | CLANG_ENABLE_MODULES = YES;
316 | CLANG_ENABLE_OBJC_ARC = YES;
317 | CLANG_WARN_BOOL_CONVERSION = YES;
318 | CLANG_WARN_CONSTANT_CONVERSION = YES;
319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
320 | CLANG_WARN_EMPTY_BODY = YES;
321 | CLANG_WARN_ENUM_CONVERSION = YES;
322 | CLANG_WARN_INT_CONVERSION = YES;
323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
324 | CLANG_WARN_UNREACHABLE_CODE = YES;
325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
326 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
327 | COPY_PHASE_STRIP = NO;
328 | CURRENT_PROJECT_VERSION = 1;
329 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
330 | ENABLE_NS_ASSERTIONS = NO;
331 | ENABLE_STRICT_OBJC_MSGSEND = YES;
332 | GCC_C_LANGUAGE_STANDARD = gnu99;
333 | GCC_NO_COMMON_BLOCKS = YES;
334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
336 | GCC_WARN_UNDECLARED_SELECTOR = YES;
337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
338 | GCC_WARN_UNUSED_FUNCTION = YES;
339 | GCC_WARN_UNUSED_VARIABLE = YES;
340 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
341 | MTL_ENABLE_DEBUG_INFO = NO;
342 | SDKROOT = iphoneos;
343 | TARGETED_DEVICE_FAMILY = "1,2";
344 | VALIDATE_PRODUCT = YES;
345 | VERSIONING_SYSTEM = "apple-generic";
346 | VERSION_INFO_PREFIX = "";
347 | };
348 | name = Release;
349 | };
350 | 3C1245801C209F1F00525217 /* Debug */ = {
351 | isa = XCBuildConfiguration;
352 | baseConfigurationReference = C57DC03E4498CE1BFA77FA1E /* Pods-CocoapodTests.debug.xcconfig */;
353 | buildSettings = {
354 | CODE_SIGN_IDENTITY = "-";
355 | COMBINE_HIDPI_IMAGES = YES;
356 | INFOPLIST_FILE = ../StoryboardKitTests/Info.plist;
357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
358 | MACOSX_DEPLOYMENT_TARGET = 10.11;
359 | PRODUCT_BUNDLE_IDENTIFIER = cc.adorkable.StoryboardKit.CocoapodTests;
360 | PRODUCT_NAME = "$(TARGET_NAME)";
361 | SDKROOT = macosx;
362 | };
363 | name = Debug;
364 | };
365 | 3C1245811C209F1F00525217 /* Release */ = {
366 | isa = XCBuildConfiguration;
367 | baseConfigurationReference = 7360C8C399AA4BCDA1485EA6 /* Pods-CocoapodTests.release.xcconfig */;
368 | buildSettings = {
369 | CODE_SIGN_IDENTITY = "-";
370 | COMBINE_HIDPI_IMAGES = YES;
371 | INFOPLIST_FILE = ../StoryboardKitTests/Info.plist;
372 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
373 | MACOSX_DEPLOYMENT_TARGET = 10.11;
374 | PRODUCT_BUNDLE_IDENTIFIER = cc.adorkable.StoryboardKit.CocoapodTests;
375 | PRODUCT_NAME = "$(TARGET_NAME)";
376 | SDKROOT = macosx;
377 | };
378 | name = Release;
379 | };
380 | /* End XCBuildConfiguration section */
381 |
382 | /* Begin XCConfigurationList section */
383 | 3C12453E1C209E1E00525217 /* Build configuration list for PBXProject "StoryboardKit" */ = {
384 | isa = XCConfigurationList;
385 | buildConfigurations = (
386 | 3C12454A1C209E1E00525217 /* Debug */,
387 | 3C12454B1C209E1E00525217 /* Release */,
388 | );
389 | defaultConfigurationIsVisible = 0;
390 | defaultConfigurationName = Release;
391 | };
392 | 3C12457F1C209F1F00525217 /* Build configuration list for PBXNativeTarget "CocoapodTests" */ = {
393 | isa = XCConfigurationList;
394 | buildConfigurations = (
395 | 3C1245801C209F1F00525217 /* Debug */,
396 | 3C1245811C209F1F00525217 /* Release */,
397 | );
398 | defaultConfigurationIsVisible = 0;
399 | defaultConfigurationName = Release;
400 | };
401 | /* End XCConfigurationList section */
402 | };
403 | rootObject = 3C12453B1C209E1E00525217 /* Project object */;
404 | }
405 |
--------------------------------------------------------------------------------
/StoryboardKit/StoryboardFileVersionedParsers/3.0/StoryboardFile3_0Parser_Views.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoryboardFile3_0Parser_Views.swift
3 | // StoryboardKit
4 | //
5 | // Created by Ian on 6/30/15.
6 | // Copyright (c) 2015 Adorkable. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import SWXMLHash
12 |
13 | // TODO: move to keypath based parsing
14 | internal extension StoryboardFile3_0Parser {
15 | // MARK: Views
16 |
17 | class ViewInstanceParseInfo {
18 | let id : String
19 | let useClass : String
20 | let viewClass : ViewClassInfo
21 | let frame : CGRect?
22 | let autoResizingMaskWidthSizable : Bool
23 | let autoResizingMaskHeightSizable : Bool
24 | let subviews : [ViewInstanceInfo]?
25 | var backgroundColor : NSColor?
26 |
27 | init(id : String, frame : CGRect?, useClass : String, viewClass : ViewClassInfo, autoResizingMaskWidthSizable : Bool, autoResizingMaskHeightSizable : Bool, subviews : [ViewInstanceInfo]?, backgroundColor : NSColor?) {
28 | self.id = id
29 |
30 | self.frame = frame
31 |
32 | self.useClass = useClass
33 | self.viewClass = viewClass
34 |
35 | self.autoResizingMaskWidthSizable = autoResizingMaskWidthSizable
36 | self.autoResizingMaskHeightSizable = autoResizingMaskHeightSizable
37 |
38 | self.subviews = subviews
39 |
40 | self.backgroundColor = backgroundColor
41 | }
42 | }
43 |
44 | internal func parseSubviews(subnode : XMLIndexer) -> [ViewInstanceInfo]? {
45 | var result : [ViewInstanceInfo]?
46 |
47 | var subviews = [ViewInstanceInfo]()
48 | for subviewNode in subnode.children
49 | {
50 | if let subviewElement = subviewNode.element
51 | {
52 | if subviewElement.name == "tableView"
53 | {
54 | if let subview = self.createTableView(subviewNode)
55 | {
56 | subviews.append(subview)
57 | } else
58 | {
59 | // TODO:
60 | }
61 | } else if subviewElement.name == "collectionView"
62 | {
63 | if let subview = self.createCollectionView(subviewNode)
64 | {
65 | subviews.append(subview)
66 | } else
67 | {
68 | // TODO:
69 | }
70 | } else
71 | {
72 | if subviewElement.name != "view"
73 | {
74 | self.Log("Unhandled subview type \(subviewElement.name), defaulting to basic view")
75 | }
76 | if let subview = self.createView(subviewNode)
77 | {
78 | subviews.append(subview)
79 | } else
80 | {
81 | // TODO:
82 | }
83 | }
84 | }
85 | }
86 | if subviews.count > 0
87 | {
88 | result = subviews
89 | }
90 |
91 | return result
92 | }
93 |
94 | internal func parseView(view : XMLIndexer, viewClassInfoClass : ViewClassInfo.Type) -> ViewInstanceParseInfo? {
95 | var result : ViewInstanceParseInfo?
96 |
97 | if let element = view.element,
98 | let id = element.allAttributes["id"]?.text
99 | {
100 | // TODO: support all View classes
101 | var useClass : String
102 | if let customClass = element.allAttributes["customClass"]?.text
103 | {
104 | useClass = customClass
105 | } else
106 | {
107 | useClass = viewClassInfoClass.defaultClass
108 | }
109 |
110 | var viewClass : ViewClassInfo
111 | if let foundViewClass = self.applicationInfo.viewClassWithClassName(useClass)
112 | {
113 | viewClass = foundViewClass
114 | } else
115 | {
116 | viewClass = viewClassInfoClass.init(className: useClass)
117 | self.applicationInfo.add(viewClass: viewClass)
118 | }
119 |
120 | var frame : CGRect?
121 | var autoResizingMaskWidthSizable : Bool = false
122 | var autoResizingMaskHeightSizable : Bool = false
123 | var subviews : [ViewInstanceInfo]?
124 | var backgroundColor : NSColor?
125 |
126 | // TODO: support subclass parser handling of subnode rather than traversing multiple times
127 | for subnode in view.children
128 | {
129 | if let subelement = subnode.element
130 | {
131 | if subelement.name == "rect" && subelement.allAttributes["key"]?.text == "frame"
132 | {
133 |
134 | frame = self.createRect(subnode)
135 |
136 | } else if subelement.name == "autoresizingMask" && subelement.allAttributes["key"]?.text == "autoresizingMask"
137 | {
138 |
139 | self.getAutoresizingMaskValues(subnode, widthSizable: &autoResizingMaskWidthSizable, heightSizable: &autoResizingMaskHeightSizable)
140 |
141 | } else if subelement.name == "subviews"
142 | {
143 |
144 | subviews = self.parseSubviews(subnode)
145 | } else if subelement.name == "color"
146 | {
147 | let color = self.createColor(subnode)
148 | if subelement.allAttributes["key"]?.text == "backgroundColor"
149 | {
150 | backgroundColor = color
151 | }
152 | } else if subelement.name == "constraints"
153 | {
154 | // TODO:
155 | }
156 | }
157 | }
158 | // var backgroundColor : NSColor? // TODO: Efff, why is there a UIColor? Make our own color object?
159 | // var constraints : [NSLayoutConstraint]? // TODO: these definitely need to be our own objects
160 | result = ViewInstanceParseInfo(id: id, frame: frame, useClass: useClass, viewClass: viewClass, autoResizingMaskWidthSizable: autoResizingMaskWidthSizable, autoResizingMaskHeightSizable: autoResizingMaskHeightSizable, subviews: subviews, backgroundColor: backgroundColor)
161 | }
162 |
163 | return result
164 | }
165 |
166 | internal func createView(view : XMLIndexer, viewClassInfoClass : ViewClassInfo.Type = ViewClassInfo.self) -> ViewInstanceInfo? {
167 | var result : ViewInstanceInfo?
168 | if let parseInfo = self.parseView(view, viewClassInfoClass: viewClassInfoClass)
169 | {
170 | let view = ViewInstanceInfo(classInfo: parseInfo.viewClass, id: parseInfo.id, frame: parseInfo.frame, autoResizingMaskWidthSizable: parseInfo.autoResizingMaskWidthSizable, autoResizingMaskHeightSizable: parseInfo.autoResizingMaskHeightSizable, subviews: parseInfo.subviews, backgroundColor: parseInfo.backgroundColor)
171 | result = view
172 | }
173 |
174 | return result
175 | }
176 |
177 | internal func createRect(rect : XMLIndexer) -> CGRect? {
178 | var result : CGRect?
179 |
180 | if let element = rect.element,
181 | let x = (element.allAttributes["x"]?.text as NSString?)?.doubleValue,
182 | let y = (element.allAttributes["y"]?.text as NSString?)?.doubleValue,
183 | let width = (element.allAttributes["width"]?.text as NSString?)?.doubleValue,
184 | let height = (element.allAttributes["height"]?.text as NSString?)?.doubleValue
185 | {
186 | result = CGRect(x: CGFloat(x), y: CGFloat(y), width: CGFloat(width), height: CGFloat(height))
187 | }
188 |
189 | return result
190 | }
191 |
192 | internal func getAutoresizingMaskValues(autoresizingMask : XMLIndexer, inout widthSizable : Bool, inout heightSizable : Bool) {
193 |
194 | if let element = autoresizingMask.element
195 | {
196 | widthSizable = element.allAttributes["widthSizable"]?.text == "YES"
197 | heightSizable = element.allAttributes["heightSizable"]?.text == "YES"
198 | }
199 | }
200 |
201 | internal func createColor(color : XMLIndexer) -> NSColor? {
202 | var result : NSColor?
203 |
204 | if let element = color.element
205 | {
206 | if let colorSpace = element.allAttributes["colorSpace"]?.text
207 | {
208 | if colorSpace == "calibratedWhite"
209 | {
210 | if let white = (element.allAttributes["white"]?.text as NSString?)?.doubleValue,
211 | let alpha = (element.allAttributes["alpha"]?.text as NSString?)?.doubleValue
212 | {
213 | result = NSColor(calibratedWhite: CGFloat(white), alpha: CGFloat(alpha))
214 | } else
215 | {
216 | self.Log("Error: Unable to find expected members of colorspace \(colorSpace)")
217 | }
218 | } else if colorSpace == "calibratedRGB"
219 | {
220 | if let red = (element.allAttributes["red"]?.text as NSString?)?.doubleValue,
221 | let green = (element.allAttributes["green"]?.text as NSString?)?.doubleValue,
222 | let blue = (element.allAttributes["green"]?.text as NSString?)?.doubleValue,
223 | let alpha = (element.allAttributes["alpha"]?.text as NSString?)?.doubleValue
224 | {
225 | result = NSColor(calibratedRed: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: CGFloat(alpha) )
226 | } else
227 | {
228 | self.Log("Error: Unable to find expected members of colorspace \(colorSpace)")
229 | }
230 | } else if colorSpace == "custom",
231 | let customColorSpace = element.allAttributes["customColorSpace"]?.text
232 | {
233 | if customColorSpace == "genericCMYKColorSpace",
234 | let cyan = (element.allAttributes["cyan"]?.text as NSString?)?.doubleValue,
235 | let magenta = (element.allAttributes["magenta"]?.text as NSString?)?.doubleValue,
236 | let yellow = (element.allAttributes["yellow"]?.text as NSString?)?.doubleValue,
237 | let black = (element.allAttributes["black"]?.text as NSString?)?.doubleValue,
238 | let alpha = (element.allAttributes["alpha"]?.text as NSString?)?.doubleValue
239 | {
240 | // TODO: what's "device" NSColor's difference?
241 | result = NSColor(deviceCyan: CGFloat(cyan), magenta: CGFloat(magenta), yellow: CGFloat(yellow), black: CGFloat(black), alpha: CGFloat(alpha) )
242 | } else
243 | {
244 | self.Log("Error: Unknown custom colorspace \(customColorSpace)")
245 | }
246 |
247 | } else
248 | {
249 | self.Log("Error: Unknown colorspace \(colorSpace)")
250 | }
251 | } else if let _ = element.allAttributes["cocoaTouchSystemColor"]?.text
252 | {
253 | // cocoaTouchSystemColor="darkTextColor"
254 | } else
255 | {
256 | self.Log("Unsupported color format: \(element)")
257 | }
258 | }
259 |
260 | return result
261 | }
262 |
263 | class TableViewInstanceParseInfo {
264 | // TODO: feels like a hack to contain the superclass's parse info
265 | let viewInstanceParseInfo : ViewInstanceParseInfo
266 | let cellPrototypes : [TableViewInstanceInfo.TableViewCellPrototypeInfo]?
267 |
268 | init(viewInstanceParseInfo : ViewInstanceParseInfo, cellPrototypes : [TableViewInstanceInfo.TableViewCellPrototypeInfo]?) {
269 | self.viewInstanceParseInfo = viewInstanceParseInfo
270 | self.cellPrototypes = cellPrototypes
271 | }
272 | }
273 |
274 | internal func parseTableView(tableView : XMLIndexer) -> TableViewInstanceParseInfo? {
275 | var result : TableViewInstanceParseInfo?
276 |
277 | if let parseInfo = self.parseView(tableView, viewClassInfoClass: TableViewClassInfo.self)
278 | {
279 | var cellPrototypes : [TableViewInstanceInfo.TableViewCellPrototypeInfo]?
280 |
281 | for subnode in tableView.children
282 | {
283 | if let subelement = subnode.element
284 | {
285 | if subelement.name == "prototypes"
286 | {
287 | cellPrototypes = self.createTableViewCellPrototypes(subnode)
288 | }
289 | }
290 | }
291 |
292 | result = TableViewInstanceParseInfo(viewInstanceParseInfo: parseInfo, cellPrototypes: cellPrototypes)
293 | }
294 |
295 | return result
296 | }
297 |
298 | internal func createTableViewCellPrototypes(prototypes : XMLIndexer) -> [TableViewInstanceInfo.TableViewCellPrototypeInfo]? {
299 | var result : [TableViewInstanceInfo.TableViewCellPrototypeInfo]?
300 |
301 | for subnode in prototypes.children
302 | {
303 | if let subelement = subnode.element
304 | {
305 | if subelement.name == "tableViewCell"
306 | {
307 | if let cellPrototype = self.createTableViewCellPrototype(subnode)
308 | {
309 | if result == nil
310 | {
311 | result = Array()
312 | }
313 |
314 | result!.append(cellPrototype)
315 | }
316 | } else
317 | {
318 | self.Log("Error: Unknown prototype type \(subelement.name)")
319 | }
320 | }
321 | }
322 |
323 | return result
324 | }
325 |
326 | internal func createTableViewCellPrototype(tableViewCell : XMLIndexer) -> TableViewInstanceInfo.TableViewCellPrototypeInfo? {
327 | var result : TableViewInstanceInfo.TableViewCellPrototypeInfo?
328 |
329 | if let element = tableViewCell.element,
330 | let id = element.allAttributes["id"]?.text
331 | {
332 | let reuseIdentifier = element.allAttributes["reuseIdentifier"]?.text
333 | result = TableViewInstanceInfo.TableViewCellPrototypeInfo(id: id, reuseIdentifier: reuseIdentifier)
334 | }
335 |
336 | return result
337 | }
338 |
339 | internal func createTableView(tableView : XMLIndexer) -> TableViewInstanceInfo? {
340 | var result : TableViewInstanceInfo?
341 | if let parseInfo = self.parseTableView(tableView)
342 | {
343 | let viewInstanceParseInfo = parseInfo.viewInstanceParseInfo
344 |
345 | let tableView = TableViewInstanceInfo(classInfo: viewInstanceParseInfo.viewClass, id: viewInstanceParseInfo.id, frame: viewInstanceParseInfo.frame, autoResizingMaskWidthSizable: viewInstanceParseInfo.autoResizingMaskWidthSizable, autoResizingMaskHeightSizable: viewInstanceParseInfo.autoResizingMaskHeightSizable, subviews: viewInstanceParseInfo.subviews, backgroundColor: viewInstanceParseInfo.backgroundColor, cellPrototypes: parseInfo.cellPrototypes)
346 | result = tableView
347 | }
348 |
349 | return result
350 | }
351 |
352 | class CollectionViewInstanceParseInfo {
353 | // TODO: feels like a hack to contain the superclass's parse info
354 | let viewInstanceParseInfo : ViewInstanceParseInfo
355 | let cellPrototypes : [CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo]?
356 |
357 | init(viewInstanceParseInfo : ViewInstanceParseInfo, cellPrototypes : [CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo]?) {
358 | self.viewInstanceParseInfo = viewInstanceParseInfo
359 | self.cellPrototypes = cellPrototypes
360 | }
361 | }
362 |
363 | internal func parseCollectionView(collectionView : XMLIndexer) -> CollectionViewInstanceParseInfo? {
364 | var result : CollectionViewInstanceParseInfo?
365 |
366 | if let parseInfo = self.parseView(collectionView, viewClassInfoClass: CollectionViewClassInfo.self)
367 | {
368 | var cellPrototypes : [CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo]?
369 |
370 | for subnode in collectionView.children
371 | {
372 | if let subelement = subnode.element
373 | {
374 | if subelement.name == "cells"
375 | {
376 | cellPrototypes = self.createCollectionViewCellPrototypes(subnode)
377 | }
378 | }
379 | }
380 |
381 | result = CollectionViewInstanceParseInfo(viewInstanceParseInfo: parseInfo, cellPrototypes: cellPrototypes)
382 | }
383 |
384 | return result
385 | }
386 |
387 | internal func createCollectionViewCellPrototypes(prototypes : XMLIndexer) -> [CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo]? {
388 | var result : [CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo]?
389 |
390 | for subnode in prototypes.children
391 | {
392 | if let subelement = subnode.element
393 | {
394 | if subelement.name == "collectionViewCell"
395 | {
396 | if let cellPrototype = self.createCollectionViewCellPrototype(subnode)
397 | {
398 | if result == nil
399 | {
400 | result = Array()
401 | }
402 |
403 | result!.append(cellPrototype)
404 | }
405 | } else
406 | {
407 | self.Log("Error: Unknown prototype type \(subelement.name)")
408 | }
409 | }
410 | }
411 |
412 | return result
413 | }
414 |
415 | internal func createCollectionViewCellPrototype(collectionViewCell : XMLIndexer) -> CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo? {
416 | var result : CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo?
417 |
418 | if let element = collectionViewCell.element,
419 | let id = element.allAttributes["id"]?.text
420 | {
421 | let reuseIdentifier = element.allAttributes["reuseIdentifier"]?.text
422 | result = CollectionViewInstanceInfo.CollectionViewCellPrototypeInfo(id: id, reuseIdentifier: reuseIdentifier)
423 | }
424 |
425 | return result
426 | }
427 |
428 | internal func createCollectionView(collectionView : XMLIndexer) -> CollectionViewInstanceInfo? {
429 | var result : CollectionViewInstanceInfo?
430 | if let parseInfo = self.parseCollectionView(collectionView)
431 | {
432 | let viewInstanceParseInfo = parseInfo.viewInstanceParseInfo
433 |
434 | let collectionView = CollectionViewInstanceInfo(classInfo: viewInstanceParseInfo.viewClass, id: viewInstanceParseInfo.id, frame: viewInstanceParseInfo.frame, autoResizingMaskWidthSizable: viewInstanceParseInfo.autoResizingMaskWidthSizable, autoResizingMaskHeightSizable: viewInstanceParseInfo.autoResizingMaskHeightSizable, subviews: viewInstanceParseInfo.subviews, backgroundColor: viewInstanceParseInfo.backgroundColor, cellPrototypes: parseInfo.cellPrototypes)
435 | result = collectionView
436 | }
437 |
438 | return result
439 | }
440 | }
--------------------------------------------------------------------------------
/StoryboardKitTests/StoryboardKit.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
--------------------------------------------------------------------------------