├── .circleci └── config.yml ├── .gitignore ├── .swiftlint.yml ├── CHANGELOG.md ├── Example ├── .swiftlint.yml ├── Default-568h@2x.png ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── Reusable.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Reusable-iOS.xcscheme │ │ │ └── Reusable-tvOS.xcscheme │ └── Target Support Files │ │ ├── Pods-ReusableDemo iOS │ │ ├── Info.plist │ │ ├── Pods-ReusableDemo iOS-Info.plist │ │ ├── Pods-ReusableDemo iOS-acknowledgements.markdown │ │ ├── Pods-ReusableDemo iOS-acknowledgements.plist │ │ ├── Pods-ReusableDemo iOS-dummy.m │ │ ├── Pods-ReusableDemo iOS-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-ReusableDemo iOS-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-ReusableDemo iOS-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-ReusableDemo iOS-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-ReusableDemo iOS-frameworks.sh │ │ ├── Pods-ReusableDemo iOS-resources.sh │ │ ├── Pods-ReusableDemo iOS-umbrella.h │ │ ├── Pods-ReusableDemo iOS.debug.xcconfig │ │ ├── Pods-ReusableDemo iOS.modulemap │ │ └── Pods-ReusableDemo iOS.release.xcconfig │ │ ├── Pods-ReusableDemo tvOS │ │ ├── Info.plist │ │ ├── Pods-ReusableDemo tvOS-Info.plist │ │ ├── Pods-ReusableDemo tvOS-acknowledgements.markdown │ │ ├── Pods-ReusableDemo tvOS-acknowledgements.plist │ │ ├── Pods-ReusableDemo tvOS-dummy.m │ │ ├── Pods-ReusableDemo tvOS-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-ReusableDemo tvOS-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-ReusableDemo tvOS-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-ReusableDemo tvOS-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-ReusableDemo tvOS-frameworks.sh │ │ ├── Pods-ReusableDemo tvOS-resources.sh │ │ ├── Pods-ReusableDemo tvOS-umbrella.h │ │ ├── Pods-ReusableDemo tvOS.debug.xcconfig │ │ ├── Pods-ReusableDemo tvOS.modulemap │ │ └── Pods-ReusableDemo tvOS.release.xcconfig │ │ ├── Reusable-iOS │ │ ├── Info.plist │ │ ├── Reusable-iOS-Info.plist │ │ ├── Reusable-iOS-dummy.m │ │ ├── Reusable-iOS-prefix.pch │ │ ├── Reusable-iOS-umbrella.h │ │ ├── Reusable-iOS.debug.xcconfig │ │ ├── Reusable-iOS.modulemap │ │ ├── Reusable-iOS.release.xcconfig │ │ └── Reusable-iOS.xcconfig │ │ └── Reusable-tvOS │ │ ├── Info.plist │ │ ├── Reusable-tvOS-Info.plist │ │ ├── Reusable-tvOS-dummy.m │ │ ├── Reusable-tvOS-prefix.pch │ │ ├── Reusable-tvOS-umbrella.h │ │ ├── Reusable-tvOS.debug.xcconfig │ │ ├── Reusable-tvOS.modulemap │ │ ├── Reusable-tvOS.release.xcconfig │ │ └── Reusable-tvOS.xcconfig ├── ReusableDemo iOS │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon-120.png │ │ │ ├── AppIcon-152.png │ │ │ ├── AppIcon-167.png │ │ │ ├── AppIcon-180.png │ │ │ ├── AppIcon-76.png │ │ │ ├── Contents.json │ │ │ └── Logo.png │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── CollectionViewCells │ │ ├── CollectionHeaderView.swift │ │ ├── CollectionHeaderView.xib │ │ ├── MyColorSquareCell.swift │ │ ├── MyStoryboardTextSquareCell.swift │ │ ├── MyXIBIndexSquaceCell.swift │ │ └── MyXIBIndexSquaceCell.xib │ ├── CollectionViewController.swift │ ├── CustomViews │ │ ├── MyCustomWidget.swift │ │ └── MyCustomWidget.xib │ ├── Info.plist │ ├── Storyboards │ │ ├── InfoDetailViewController.swift │ │ ├── InfoViewController.storyboard │ │ └── InfoViewController.swift │ ├── TableViewCells │ │ ├── MyHeaderTableView.swift │ │ ├── MyHeaderTableView.xib │ │ ├── MySimpleColorCell.swift │ │ ├── MyStoryBoardIndexPathCell.swift │ │ ├── MyXIBInfoCell.swift │ │ ├── MyXIBInfoCell.xib │ │ ├── MyXIBTextCell.swift │ │ └── MyXIBTextCell.xib │ └── TableViewController.swift ├── ReusableDemo tvOS │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── App Icon & Top Shelf Image.brandassets │ │ │ ├── App Icon - Large.imagestack │ │ │ │ ├── Back.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ ├── AppleTV.png │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Front.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ ├── AppleTV.png │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Middle.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ ├── AppleTV.png │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ ├── App Icon - Small.imagestack │ │ │ │ ├── Back.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Front.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ ├── AppleTV-small.png │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Middle.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ ├── AppleTV-small.png │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Top Shelf Image Wide.imageset │ │ │ │ └── Contents.json │ │ │ └── Top Shelf Image.imageset │ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Info.plist │ ├── MyCustomWidget.swift │ └── MyCustomWidget.xib ├── ReusableDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── ReusableDemo iOS.xcscheme │ │ └── ReusableDemo tvOS.xcscheme └── ReusableDemo.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Logo.png ├── Logo.xcf ├── NibOwnerLoadable-InStoryboard.png ├── NibOwnerLoadable.png ├── Package.swift ├── README.md ├── Rakefile ├── Reusable.podspec ├── Sources ├── Storyboard │ ├── StoryboardBased.swift │ └── StoryboardSceneBased.swift └── View │ ├── NibLoadable.swift │ ├── NibOwnerLoadable.swift │ ├── Reusable.swift │ ├── UICollectionView+Reusable.swift │ └── UITableView+Reusable.swift └── _Pods.xcodeproj /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | defaults: 2 | - &default-config 3 | macos: 4 | xcode: 12.5.1 5 | shell: /bin/bash --login -eo pipefail 6 | environment: 7 | CIRCLE_ARTIFACTS: /tmp/circleci-artifacts 8 | CIRCLE_TEST_REPORTS: /tmp/circleci-test-results 9 | BUNDLE_PATH: vendor/bundle 10 | - &prepare-storage 11 | run: 12 | name: Create directories for artifacts and reports 13 | command: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS 14 | - &set-ruby-version 15 | run: 16 | name: Set Ruby Version 17 | command: echo 'chruby ruby-2.7.3' >> ~/.bash_profile 18 | - &restore-gems 19 | restore_cache: 20 | keys: 21 | - gems-{{ checksum "Gemfile.lock" }} 22 | - gems- 23 | - &install-gems 24 | run: 25 | name: Bundle install 26 | command: bundle check || bundle install 27 | environment: 28 | BUNDLE_JOBS: 4 29 | BUNDLE_RETRY: 3 30 | - &store-gems 31 | save_cache: 32 | key: gems-{{ checksum "Gemfile.lock" }} 33 | paths: 34 | - vendor/bundle 35 | - &fetch-xcode-logs 36 | run: 37 | name: Getting Xcode activity logs 38 | command: find $HOME/Library/Developer/Xcode/DerivedData -name '*.xcactivitylog' -exec cp {} $CIRCLE_ARTIFACTS/xcactivitylog \; || true 39 | - &store-artifacts 40 | store_artifacts: 41 | path: /tmp/circleci-artifacts 42 | 43 | 44 | version: 2 45 | jobs: 46 | lint: 47 | <<: *default-config 48 | steps: 49 | - *prepare-storage 50 | - checkout 51 | - *set-ruby-version 52 | - *restore-gems 53 | - *install-gems 54 | - *store-gems 55 | - run: 56 | name: Install SwiftLint 57 | command: bundle exec rake swiftlint:install 58 | - run: 59 | name: Lint source code 60 | command: bundle exec rake swiftlint:run 61 | - *store-artifacts 62 | 63 | spm-build: 64 | <<: *default-config 65 | steps: 66 | - *prepare-storage 67 | - checkout 68 | - *set-ruby-version 69 | - *restore-gems 70 | - *install-gems 71 | - *store-gems 72 | - run: 73 | name: SPM Build 74 | command: bundle exec rake spm:build 75 | - *store-artifacts 76 | 77 | xcode-ios-build: 78 | <<: *default-config 79 | steps: 80 | - *prepare-storage 81 | - checkout 82 | - *set-ruby-version 83 | - *restore-gems 84 | - *install-gems 85 | - *store-gems 86 | - run: 87 | name: Build iOS Framework 88 | command: bundle exec rake fmk:ios 89 | - run: 90 | name: Build iOS Demo 91 | command: bundle exec rake demo:ios 92 | - store_test_results: 93 | path: /tmp/circleci-test-results 94 | - *fetch-xcode-logs 95 | - *store-artifacts 96 | 97 | xcode-tvos-build: 98 | <<: *default-config 99 | steps: 100 | - *prepare-storage 101 | - checkout 102 | - *set-ruby-version 103 | - *restore-gems 104 | - *install-gems 105 | - *store-gems 106 | - run: 107 | name: Build tvOS Framework 108 | command: bundle exec rake fmk:tvos 109 | - run: 110 | name: Build tvOS Demo 111 | command: bundle exec rake demo:tvos 112 | - store_test_results: 113 | path: /tmp/circleci-test-results 114 | - *fetch-xcode-logs 115 | - *store-artifacts 116 | 117 | pod-lint: 118 | <<: *default-config 119 | steps: 120 | - *prepare-storage 121 | - checkout 122 | - *set-ruby-version 123 | - *restore-gems 124 | - *install-gems 125 | - *store-gems 126 | - run: 127 | name: Lint podspec 128 | command: bundle exec rake pod:lint 129 | - *store-artifacts 130 | 131 | carthage-build: 132 | <<: *default-config 133 | steps: 134 | - *prepare-storage 135 | - checkout 136 | - *set-ruby-version 137 | - *restore-gems 138 | - *install-gems 139 | - *store-gems 140 | - run: 141 | name: Install Carthage 142 | command: bundle exec rake carthage:install 143 | - run: 144 | name: Carthage Build 145 | command: bundle exec rake carthage:build 146 | - store_test_results: 147 | path: /tmp/circleci-test-results 148 | - *fetch-xcode-logs 149 | - *store-artifacts 150 | 151 | workflows: 152 | version: 2 153 | check_all_builds: 154 | jobs: 155 | - lint 156 | - xcode-ios-build: 157 | requires: 158 | - lint 159 | - xcode-tvos-build: 160 | requires: 161 | - lint 162 | - spm-build: 163 | requires: 164 | - lint 165 | - carthage-build: 166 | requires: 167 | - xcode-ios-build 168 | - xcode-tvos-build 169 | - pod-lint: 170 | requires: 171 | - spm-build 172 | - xcode-ios-build 173 | - xcode-tvos-build 174 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## macOS 2 | 3 | .DS_Store 4 | 5 | ## Xcode 6 | 7 | ### Build generated 8 | build/ 9 | DerivedData 10 | 11 | ### Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata 21 | 22 | ### Other 23 | *.xccheckout 24 | *.moved-aside 25 | *.xcuserstate 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | 32 | 33 | ## Swift Package Manager 34 | 35 | .swiftpm 36 | .build/ 37 | 38 | ## Carthage 39 | 40 | Carthage/ 41 | Reusable.framework.zip 42 | 43 | ## fastlane 44 | 45 | fastlane/report.xml 46 | fastlane/screenshots 47 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 2 | warning: 120 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## main branch 4 | 5 | _No pending changes to be released yet!_ 6 | 7 | ## 4.1.2 8 | 9 | * Update `Package.swift` and `.podspec` to use newer min iOS version supported by Xcode 12+. 10 | [@AliSoftware](https://github.com/AliSoftware) 11 | [#115](https://github.com/AliSoftware/Reusable/pull/115) 12 | 13 | * Fix Xcode 12.5 warnings about the class keyword for protocol inheritance that is deprecated. 14 | [@johnarn](https://github.com/johnarn) 15 | [#113](https://github.com/AliSoftware/Reusable/pull/113) 16 | 17 | ## 4.1.1 18 | 19 | * Update the README with up-to-date Swift versions and Installation Instructions. 20 | [@kuyazee](https://github.com/kuyazee) 21 | [@AliSoftware](https://github.com/AliSoftware) 22 | [#95](https://github.com/AliSoftware/Reusable/pull/95) 23 | 24 | * Set `APPLICATION_EXTENSION_API_ONLY` build setting on built frameworks. 25 | [@AliSoftware](https://github.com/AliSoftware) 26 | [#98](https://github.com/AliSoftware/Reusable/pull/98) 27 | [@nahung89](https://github.com/nahung89) 28 | [#88](https://github.com/AliSoftware/Reusable/pull/88) 29 | 30 | * Update tools used by the project (Xcode, CocoaPods, CI, Carthage). 31 | Also SPM builds are now tested by CI. 32 | [@AliSoftware](https://github.com/AliSoftware) 33 | [#97](https://github.com/AliSoftware/Reusable/pull/97) 34 | 35 | * Update SPM `Package.swift` to mention supported platforms. 36 | [@MortyMerr](https://github.com/MortyMerr) 37 | [#89](https://github.com/AliSoftware/Reusable/pull/89) 38 | [@pahnev](https://github.com/pahnev) 39 | [#93](https://github.com/AliSoftware/Reusable/pull/93) 40 | [@mackoj](https://github.com/mackoj) 41 | [#85](https://github.com/AliSoftware/Reusable/pull/85) 42 | 43 | * Fix nib name lookup when using subclassing. 44 | [@calmez](https://github.com/calmez) 45 | [#96](https://github.com/AliSoftware/Reusable/pull/96) 46 | 47 | ## 4.1.0 48 | 49 | * Support for Swift 5.0 50 | [@florentmorin](https://github.com/florentmorin) 51 | [#80](https://github.com/AliSoftware/Reusable/pull/80) 52 | 53 | ## 4.0.5 54 | 55 | * Fix for only allowing the use of app extension API. 56 | [@igorkulman](https://github.com/igorkulman) 57 | [#73](https://github.com/AliSoftware/Reusable/pull/73) 58 | 59 | ## 4.0.4 60 | 61 | * Only allowing the use of app extension API so using the library in an app extension does not produce a warning. 62 | [@igorkulman](https://github.com/igorkulman) 63 | [#70](https://github.com/AliSoftware/Reusable/pull/70) 64 | 65 | ## 4.0.3 66 | 67 | * Upgrade to CircleCI 2. 68 | [@djbe](https://github.com/djbe) 69 | [#60](https://github.com/AliSoftware/Reusable/pull/60) 70 | 71 | * Update project to support Swift 4.2. 72 | [@djbe](https://github.com/djbe) 73 | [#58](https://github.com/AliSoftware/Reusable/pull/58) 74 | 75 | ## 4.0.2 76 | 77 | * Update project to support Swift 4. 78 | [@AYastrebov](https://github.com/AYastrebov) 79 | [#54](https://github.com/AliSoftware/Reusable/pull/54) 80 | 81 | * Fix typo in StoryboardBased examples. 82 | [@danshevluk](https://github.com/danshevluk) 83 | [#42](https://github.com/AliSoftware/Reusable/pull/42) 84 | 85 | * Updated README instructions to Swift 3. 86 | [@neilkimmett](https://github.com/neilkimmett) 87 | [#41](https://github.com/AliSoftware/Reusable/pull/41) 88 | 89 | ## 4.0.1 90 | 91 | * Added a tvOS target in the Example project. 92 | * Carthage should now see the tvOS framework 93 | 94 | ## 4.0.0 95 | 96 | ### Breaking changes 97 | 98 | * The method `static func loadFromNib(owner:)` of `NibOwnerLoadable` has been replaced by instance method `func loadNibContent()`. 99 | This is more consistent as we need an instance (owner) anyway, and also avoids possible crashes when used with `UIView` subclasses 100 | not implementing non-required initializers `init()`/`init(frame:)`. 101 | _(Method `static func loadFromNib()` of `NibLoadable` is still unchanged)_. 102 | [@Skoti](https://github.com/Skoti) 103 | [#40](https://github.com/AliSoftware/Reusable/pull/40) 104 | * The `storyboard` property of `StoryboardBased` and `StoryboardSceneBased` protocols has been renamed to `sceneStoryboard` to avoid conflicts. 105 | [@jakubgert](https://github.com/jakubgert) 106 | [#33](https://github.com/AliSoftware/Reusable/pull/33) 107 | 108 | ### Fixes 109 | 110 | * Fixing documentation typos for `CollectionHeaderView` and `MyXIBIndexSquaceCell`. 111 | [@Skoti](https://github.com/Skoti) 112 | 113 | * Fixing TableView Controller scene in Example project, to display cells above `UITabBar`. 114 | [@Skoti](https://github.com/Skoti) 115 | 116 | ## 3.0.1 117 | 118 | ### Bug Fixes 119 | 120 | * Fix `instantiate()` implementation on `StoryboardSceneBased` ViewControllers. 121 | [@jakubgert](https://github.com/jakubgert) 122 | [#38](https://github.com/AliSoftware/Reusable/pull/38) 123 | * Removed strict `NibReusable` protocol conforming in `register` functions. 124 | You can now make a `Reusable`-only cell with a `NibLoadable` subclass. 125 | [@nekrich](https://github.com/nekrich) 126 | [#37](https://github.com/AliSoftware/Reusable/pull/37) 127 | 128 | ## 3.0.0 129 | 130 | ### Breaking Changes 131 | 132 | * Converted library and Demo project to Swift 3. 133 | ⚠️ The following methods have new signatures: 134 | - `dequeueReusableCell(indexPath:)` is now `dequeueReusableCell(for:)` 135 | - `dequeueReusableCell(indexPath:cellType:)` is now `dequeueReusableCell(for:cellType:)` 136 | - `registerReusableCell(_:)` is now `register(cellType:)` 137 | - `registerReusableHeaderFooterView(_:)` is now `register(headerFooterViewType:)` 138 | - `registerReusableSupplementaryView(_:viewType:)` is now `register(supplementaryViewType:ofKind:)` 139 | - `dequeueReusableSupplementaryView(_:indexPath:viewType:)` is now `dequeueReusableSupplementaryView(ofKind:for:viewType:)` 140 | [@phatblat](https://github.com/phatblat) 141 | [#30](https://github.com/AliSoftware/Reusable/pull/30) 142 | [@ceyhuno](https://github.com/ceyhuno) 143 | [#31](https://github.com/AliSoftware/Reusable/pull/31) 144 | 145 | ## 2.5.1 146 | 147 | * Adapted source files and demo project for Swift 2.3 148 | [@antondomashnev](https://github.com/Antondomashnev) 149 | [#16](https://github.com/AliSoftware/Reusable/pull/28) 150 | 151 | ## 2.5.0 152 | 153 | * Added the possibility for `NibOwnerLoadable` confirming custom views to pass an existing instance as `owner` 154 | (used as the File's Owner) in case one already exists. This is especially useful to implement `init(coder:)` 155 | to load the content of the XIB as subviews of `self` after initialization. See `MyCustomWidget.swift` for an example. 156 | [@AliSoftware](https://github.com/AliSoftware) 157 | 158 | ## 2.4.0 159 | 160 | * Added `StoryboardBased` and `StoryboardSceneBased` protocols for storyboard based `UIViewController` easy instantiation. 161 | [@AliSoftware](https://github.com/AliSoftware) 162 | 163 | ## 2.3.0 164 | 165 | * Added ` NibOwnerLoadable` protocol for `UIView` set as XIB's File's Owner. 166 | [@PoissonBallon](https://github.com/PoissonBallon) 167 | [#16](https://github.com/AliSoftware/Reusable/pull/16) 168 | 169 | _While the `NibLoadable` protocol is adapted to views loaded from XIB but that are set as the root view of the XIB, 170 | this new `NibOwnerLoadable` protocol is adapted to view loaded from XIB too, but that are set as the XIB's File's Owner._ 171 | 172 | ## 2.2.1 173 | 174 | * Fixed issue with `register…` methods registering the superclass `T` instead of the dynamic class `cellType` / `viewType`. 175 | [@narirou](https://github.com/narirou) 176 | [#13](https://github.com/AliSoftware/Reusable/pull/13) 177 | 178 | ## 2.2.0 179 | 180 | * Added optional `viewType` & `cellType` parameters to the dequeue functions. 181 | [@k3zi](https://github.com/k3zi) 182 | [#11](https://github.com/AliSoftware/Reusable/pull/11) 183 | 184 | This parameter is only needed if you can't write `… as MyCell` (to let Swift infer the cell type from the return type), 185 | which might be the case for example when your cell class is stored in a variable: 186 | 187 | ```swift 188 | let cellType: Any.Type = self.cellTypeForIndexPath(indexPath) 189 | // Can't do this in this case (because cellType is a variable): 190 | let cell = tableView.dequeueReusableCell(indexPath: indexPath) as cellType ❌ // compiler error 191 | // But now we can use that alternate way for such cases: 192 | let cell = tableView.dequeueReusableCell(indexPath: indexPath, cellType: cellType) 193 | ``` 194 | 195 | But if you know the type at compile time, you can omit the `cellType` parameter and still do this, letting the return type infer it for you: 196 | 197 | ```swift 198 | let cell = tableView.dequeueReusableCell(indexPath: indexPath) as MyCell 199 | ``` 200 | 201 | ## 2.1.1 202 | 203 | * Made every method `final` to allow more optimizations. 204 | [@AliSoftware](https://github.com/AliSoftware) 205 | 206 | * Banned the use of `as!` in the source code in favour of `guard let x = y else { fatalError(…) }`. 207 | This avoids force-casts (which are considered bad practice) and generate a more explicit fatal error in case the developer forgot something (typically forgot to set the reuseIdentifier in IB). 208 | [@AliSoftware](https://github.com/AliSoftware) 209 | [#6](https://github.com/AliSoftware/Reusable/issues/6) 210 | 211 | * Fixed bundle location of nibs. By default, `nib: UINib` of `NibLoadable` protocol will now use the nib located in the bundle of the conforming class. 212 | [@chrisamanse](https://github.com/chrisamanse) 213 | [#10](https://github.com/AliSoftware/Reusable/pull/10) 214 | 215 | * Fixed issue with subclasses of types conforming to `Reusable` — due to the [Swift bug SR-617](https://bugs.swift.org/browse/SR-617). 216 | [@chrisamanse](https://github.com/chrisamanse) 217 | [#2](https://github.com/AliSoftware/Reusable/issues/2) 218 | 219 | ## 2.1.0 220 | 221 | * Added support for direct instantiation of arbitrary `UIView` from a nib. 222 | [@jakubvano](https://github.com/jakubvano) 223 | [#5](https://github.com/AliSoftware/Reusable/pull/5) 224 | 225 | There is now a dedicated `NibLoadable` protocol which can be used on any arbitrary `UIView` (even non-"reusable" views) to load it from a XIB (via the `loadFromNib()` function injected via the protocol extension). 226 | 227 | _The `NibReusable` protocol still exists for reusable cells but is now declared just as a combination of both the `Reusable` and `NibLoadable` protocols. 228 | 229 | ## 2.0.0 230 | 231 | * Fixed missing `public` visibility for the protocols and extensions 232 | * Improved README documentation 233 | 234 | ## 1.1.0 235 | 236 | * Added documentation 237 | * Fixed generic constraints on the API working with `UICollectionView`'s `SupplementaryView` 238 | * Updated Example project to add an UICollectionView with cells from XIB & Code + Header views 239 | 240 | ## 1.0.0 241 | 242 | * Split protocol in two: `Reusable` and `NibReusable` 243 | * Now contains a Demo project 244 | 245 | ## 0.1.0 246 | 247 | Initial version. Only one `Reusable` protocol 248 | No demo project, but has a `podspec` and a `Package.swift` 249 | -------------------------------------------------------------------------------- /Example/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - empty_count 3 | 4 | included: 5 | - ../Sources 6 | - ReusableDemo 7 | 8 | line_length: 9 | warning: 120 10 | error: 160 11 | 12 | -------------------------------------------------------------------------------- /Example/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/Default-568h@2x.png -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'ReusableDemo iOS' do 4 | platform :ios, '12.0' 5 | pod 'Reusable', :path => '../' 6 | end 7 | 8 | target 'ReusableDemo tvOS' do 9 | platform :tvos, '12.0' 10 | pod 'Reusable', :path => '../' 11 | end 12 | 13 | post_install do |installer| 14 | installer.pods_project.targets.each do |target| 15 | target.build_configurations.each do |config| 16 | config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES' 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Reusable (4.1.2): 3 | - Reusable/Storyboard (= 4.1.2) 4 | - Reusable/View (= 4.1.2) 5 | - Reusable/Storyboard (4.1.2) 6 | - Reusable/View (4.1.2) 7 | 8 | DEPENDENCIES: 9 | - Reusable (from `../`) 10 | 11 | EXTERNAL SOURCES: 12 | Reusable: 13 | :path: "../" 14 | 15 | SPEC CHECKSUMS: 16 | Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 17 | 18 | PODFILE CHECKSUM: ae97c8d84b9148534471b041a33cec1ba3620b65 19 | 20 | COCOAPODS: 1.11.0 21 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/Reusable.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Reusable", 3 | "cocoapods_version": "~> 1.4", 4 | "version": "4.1.2", 5 | "summary": "A Swift Mixin to deal with reusable UITableView & UICollectionView cells and XIB-based views", 6 | "description": "Reusable is a [Swift Mixin](http://alisoftware.github.io/swift/protocol/2015/11/08/mixins-over-inheritance/)\nto easily deal with your reusable UITableViewCell and UICollectionViewCell classes.\n\nSimply mark your `UITableViewCell` or `UICollectionViewCell` sublcasses as\nconforming to either `Reusable` or `NibReusable` and you'll be able to\nmanipulate them way easier, and without worrying with String-type reuseIdentifiers\never again, and instead use them in a type-safe manner!\n\nReusable also support marking any arbitrary `UIView` subclass as `NibLoadable` so that\nyou can then call `loadFromNib()` on the custom view class easily without adding any code.\n\nFor more info, see [my blog post](http://alisoftware.github.io/swift/generics/2016/01/06/generic-tableviewcells/)\nabout this technique.", 7 | "homepage": "https://github.com/AliSoftware/Reusable", 8 | "license": { 9 | "type": "MIT", 10 | "file": "LICENSE" 11 | }, 12 | "authors": { 13 | "Olivier Halligon": "olivier@halligon.net" 14 | }, 15 | "social_media_url": "http://twitter.com/aligatr", 16 | "platforms": { 17 | "ios": "9.0", 18 | "tvos": "9.0" 19 | }, 20 | "source": { 21 | "git": "https://github.com/AliSoftware/Reusable.git", 22 | "tag": "4.1.2" 23 | }, 24 | "swift_versions": "5.0", 25 | "frameworks": "UIKit", 26 | "subspecs": [ 27 | { 28 | "name": "View", 29 | "source_files": "Sources/View/*.swift" 30 | }, 31 | { 32 | "name": "Storyboard", 33 | "source_files": "Sources/Storyboard/*.swift" 34 | } 35 | ], 36 | "swift_version": "5.0" 37 | } 38 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Reusable (4.1.2): 3 | - Reusable/Storyboard (= 4.1.2) 4 | - Reusable/View (= 4.1.2) 5 | - Reusable/Storyboard (4.1.2) 6 | - Reusable/View (4.1.2) 7 | 8 | DEPENDENCIES: 9 | - Reusable (from `../`) 10 | 11 | EXTERNAL SOURCES: 12 | Reusable: 13 | :path: "../" 14 | 15 | SPEC CHECKSUMS: 16 | Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 17 | 18 | PODFILE CHECKSUM: ae97c8d84b9148534471b041a33cec1ba3620b65 19 | 20 | COCOAPODS: 1.11.0 21 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Reusable-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Reusable-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/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 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-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 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Reusable 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2016 AliSoftware 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | Generated by CocoaPods - https://cocoapods.org 29 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2016 AliSoftware 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | License 40 | MIT 41 | Title 42 | Reusable 43 | Type 44 | PSGroupSpecifier 45 | 46 | 47 | FooterText 48 | Generated by CocoaPods - https://cocoapods.org 49 | Title 50 | 51 | Type 52 | PSGroupSpecifier 53 | 54 | 55 | StringsTable 56 | Acknowledgements 57 | Title 58 | Acknowledgements 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ReusableDemo_iOS : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ReusableDemo_iOS 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Reusable-iOS/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Reusable-iOS/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | BCSYMBOLMAP_DIR="BCSymbolMaps" 23 | 24 | 25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 28 | 29 | # Copies and strips a vendored framework 30 | install_framework() 31 | { 32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 33 | local source="${BUILT_PRODUCTS_DIR}/$1" 34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 36 | elif [ -r "$1" ]; then 37 | local source="$1" 38 | fi 39 | 40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 41 | 42 | if [ -L "${source}" ]; then 43 | echo "Symlinked..." 44 | source="$(readlink "${source}")" 45 | fi 46 | 47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then 48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied 49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do 50 | echo "Installing $f" 51 | install_bcsymbolmap "$f" "$destination" 52 | rm "$f" 53 | done 54 | rmdir "${source}/${BCSYMBOLMAP_DIR}" 55 | fi 56 | 57 | # Use filter instead of exclude so missing patterns don't throw errors. 58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 60 | 61 | local basename 62 | basename="$(basename -s .framework "$1")" 63 | binary="${destination}/${basename}.framework/${basename}" 64 | 65 | if ! [ -r "$binary" ]; then 66 | binary="${destination}/${basename}" 67 | elif [ -L "${binary}" ]; then 68 | echo "Destination binary is symlinked..." 69 | dirname="$(dirname "${binary}")" 70 | binary="${dirname}/$(readlink "${binary}")" 71 | fi 72 | 73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 75 | strip_invalid_archs "$binary" 76 | fi 77 | 78 | # Resign the code if required by the build settings to avoid unstable apps 79 | code_sign_if_enabled "${destination}/$(basename "$1")" 80 | 81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 83 | local swift_runtime_libs 84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 85 | for lib in $swift_runtime_libs; do 86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 88 | code_sign_if_enabled "${destination}/${lib}" 89 | done 90 | fi 91 | } 92 | # Copies and strips a vendored dSYM 93 | install_dsym() { 94 | local source="$1" 95 | warn_missing_arch=${2:-true} 96 | if [ -r "$source" ]; then 97 | # Copy the dSYM into the targets temp dir. 98 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 99 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 100 | 101 | local basename 102 | basename="$(basename -s .dSYM "$source")" 103 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 105 | 106 | # Strip invalid architectures from the dSYM. 107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 108 | strip_invalid_archs "$binary" "$warn_missing_arch" 109 | fi 110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then 111 | # Move the stripped file into its final destination. 112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 114 | else 115 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}" 117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 118 | fi 119 | fi 120 | } 121 | 122 | # Used as a return value for each invocation of `strip_invalid_archs` function. 123 | STRIP_BINARY_RETVAL=0 124 | 125 | # Strip invalid architectures 126 | strip_invalid_archs() { 127 | binary="$1" 128 | warn_missing_arch=${2:-true} 129 | # Get architectures for current target binary 130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 131 | # Intersect them with the architectures we are building for 132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 133 | # If there are no archs supported by this binary then warn the user 134 | if [[ -z "$intersected_archs" ]]; then 135 | if [[ "$warn_missing_arch" == "true" ]]; then 136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 137 | fi 138 | STRIP_BINARY_RETVAL=1 139 | return 140 | fi 141 | stripped="" 142 | for arch in $binary_archs; do 143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 144 | # Strip non-valid architectures in-place 145 | lipo -remove "$arch" -output "$binary" "$binary" 146 | stripped="$stripped $arch" 147 | fi 148 | done 149 | if [[ "$stripped" ]]; then 150 | echo "Stripped $binary of architectures:$stripped" 151 | fi 152 | STRIP_BINARY_RETVAL=0 153 | } 154 | 155 | # Copies the bcsymbolmap files of a vendored framework 156 | install_bcsymbolmap() { 157 | local bcsymbolmap_path="$1" 158 | local destination="${BUILT_PRODUCTS_DIR}" 159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 161 | } 162 | 163 | # Signs a framework with the provided identity 164 | code_sign_if_enabled() { 165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 166 | # Use the current code_sign_identity 167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 169 | 170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 171 | code_sign_cmd="$code_sign_cmd &" 172 | fi 173 | echo "$code_sign_cmd" 174 | eval "$code_sign_cmd" 175 | fi 176 | } 177 | 178 | if [[ "$CONFIGURATION" == "Debug" ]]; then 179 | install_framework "${BUILT_PRODUCTS_DIR}/Reusable-iOS/Reusable.framework" 180 | fi 181 | if [[ "$CONFIGURATION" == "Release" ]]; then 182 | install_framework "${BUILT_PRODUCTS_DIR}/Reusable-iOS/Reusable.framework" 183 | fi 184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 185 | wait 186 | fi 187 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ReusableDemo_iOSVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ReusableDemo_iOSVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS/Reusable.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "Reusable" -framework "UIKit" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ReusableDemo_iOS { 2 | umbrella header "Pods-ReusableDemo iOS-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS/Reusable.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "Reusable" -framework "UIKit" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/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 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-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 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Reusable 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2016 AliSoftware 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | Generated by CocoaPods - https://cocoapods.org 29 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2016 AliSoftware 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | License 40 | MIT 41 | Title 42 | Reusable 43 | Type 44 | PSGroupSpecifier 45 | 46 | 47 | FooterText 48 | Generated by CocoaPods - https://cocoapods.org 49 | Title 50 | 51 | Type 52 | PSGroupSpecifier 53 | 54 | 55 | StringsTable 56 | Acknowledgements 57 | Title 58 | Acknowledgements 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ReusableDemo_tvOS : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ReusableDemo_tvOS 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Reusable-tvOS/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Reusable-tvOS/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reusable.framework -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | BCSYMBOLMAP_DIR="BCSymbolMaps" 23 | 24 | 25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 28 | 29 | # Copies and strips a vendored framework 30 | install_framework() 31 | { 32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 33 | local source="${BUILT_PRODUCTS_DIR}/$1" 34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 36 | elif [ -r "$1" ]; then 37 | local source="$1" 38 | fi 39 | 40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 41 | 42 | if [ -L "${source}" ]; then 43 | echo "Symlinked..." 44 | source="$(readlink "${source}")" 45 | fi 46 | 47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then 48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied 49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do 50 | echo "Installing $f" 51 | install_bcsymbolmap "$f" "$destination" 52 | rm "$f" 53 | done 54 | rmdir "${source}/${BCSYMBOLMAP_DIR}" 55 | fi 56 | 57 | # Use filter instead of exclude so missing patterns don't throw errors. 58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 60 | 61 | local basename 62 | basename="$(basename -s .framework "$1")" 63 | binary="${destination}/${basename}.framework/${basename}" 64 | 65 | if ! [ -r "$binary" ]; then 66 | binary="${destination}/${basename}" 67 | elif [ -L "${binary}" ]; then 68 | echo "Destination binary is symlinked..." 69 | dirname="$(dirname "${binary}")" 70 | binary="${dirname}/$(readlink "${binary}")" 71 | fi 72 | 73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 75 | strip_invalid_archs "$binary" 76 | fi 77 | 78 | # Resign the code if required by the build settings to avoid unstable apps 79 | code_sign_if_enabled "${destination}/$(basename "$1")" 80 | 81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 83 | local swift_runtime_libs 84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 85 | for lib in $swift_runtime_libs; do 86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 88 | code_sign_if_enabled "${destination}/${lib}" 89 | done 90 | fi 91 | } 92 | # Copies and strips a vendored dSYM 93 | install_dsym() { 94 | local source="$1" 95 | warn_missing_arch=${2:-true} 96 | if [ -r "$source" ]; then 97 | # Copy the dSYM into the targets temp dir. 98 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 99 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 100 | 101 | local basename 102 | basename="$(basename -s .dSYM "$source")" 103 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 105 | 106 | # Strip invalid architectures from the dSYM. 107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 108 | strip_invalid_archs "$binary" "$warn_missing_arch" 109 | fi 110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then 111 | # Move the stripped file into its final destination. 112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 114 | else 115 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}" 117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 118 | fi 119 | fi 120 | } 121 | 122 | # Used as a return value for each invocation of `strip_invalid_archs` function. 123 | STRIP_BINARY_RETVAL=0 124 | 125 | # Strip invalid architectures 126 | strip_invalid_archs() { 127 | binary="$1" 128 | warn_missing_arch=${2:-true} 129 | # Get architectures for current target binary 130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 131 | # Intersect them with the architectures we are building for 132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 133 | # If there are no archs supported by this binary then warn the user 134 | if [[ -z "$intersected_archs" ]]; then 135 | if [[ "$warn_missing_arch" == "true" ]]; then 136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 137 | fi 138 | STRIP_BINARY_RETVAL=1 139 | return 140 | fi 141 | stripped="" 142 | for arch in $binary_archs; do 143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 144 | # Strip non-valid architectures in-place 145 | lipo -remove "$arch" -output "$binary" "$binary" 146 | stripped="$stripped $arch" 147 | fi 148 | done 149 | if [[ "$stripped" ]]; then 150 | echo "Stripped $binary of architectures:$stripped" 151 | fi 152 | STRIP_BINARY_RETVAL=0 153 | } 154 | 155 | # Copies the bcsymbolmap files of a vendored framework 156 | install_bcsymbolmap() { 157 | local bcsymbolmap_path="$1" 158 | local destination="${BUILT_PRODUCTS_DIR}" 159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 161 | } 162 | 163 | # Signs a framework with the provided identity 164 | code_sign_if_enabled() { 165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 166 | # Use the current code_sign_identity 167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 169 | 170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 171 | code_sign_cmd="$code_sign_cmd &" 172 | fi 173 | echo "$code_sign_cmd" 174 | eval "$code_sign_cmd" 175 | fi 176 | } 177 | 178 | if [[ "$CONFIGURATION" == "Debug" ]]; then 179 | install_framework "${BUILT_PRODUCTS_DIR}/Reusable-tvOS/Reusable.framework" 180 | fi 181 | if [[ "$CONFIGURATION" == "Release" ]]; then 182 | install_framework "${BUILT_PRODUCTS_DIR}/Reusable-tvOS/Reusable.framework" 183 | fi 184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 185 | wait 186 | fi 187 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ReusableDemo_tvOSVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ReusableDemo_tvOSVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS/Reusable.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "Reusable" -framework "UIKit" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ReusableDemo_tvOS { 2 | umbrella header "Pods-ReusableDemo tvOS-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS/Reusable.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "Reusable" -framework "UIKit" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/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 | 4.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS-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 | 4.1.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Reusable_iOS : NSObject 3 | @end 4 | @implementation PodsDummy_Reusable_iOS 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ReusableVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ReusableVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_LDFLAGS = $(inherited) -framework "UIKit" 6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS.modulemap: -------------------------------------------------------------------------------- 1 | framework module Reusable { 2 | umbrella header "Reusable-iOS-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_LDFLAGS = $(inherited) -framework "UIKit" 6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-iOS/Reusable-iOS.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Reusable-iOS 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "UIKit" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/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 | 4.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS-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 | 4.1.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Reusable_tvOS : NSObject 3 | @end 4 | @implementation PodsDummy_Reusable_tvOS 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ReusableVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ReusableVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_LDFLAGS = $(inherited) -framework "UIKit" 6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS.modulemap: -------------------------------------------------------------------------------- 1 | framework module Reusable { 2 | umbrella header "Reusable-tvOS-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_LDFLAGS = $(inherited) -framework "UIKit" 6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Reusable-tvOS/Reusable-tvOS.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Reusable-tvOS 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "UIKit" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, 17 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | } 22 | 23 | // Swift < 4.2 support 24 | #if !(swift(>=4.2)) 25 | extension UIApplication { 26 | typealias LaunchOptionsKey = UIApplicationLaunchOptionsKey 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-120.png -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-152.png -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-167.png -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-180.png -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/AppIcon-76.png -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon-120.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "AppIcon-180.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "ipad", 47 | "size" : "20x20", 48 | "scale" : "1x" 49 | }, 50 | { 51 | "idiom" : "ipad", 52 | "size" : "20x20", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "idiom" : "ipad", 57 | "size" : "29x29", 58 | "scale" : "1x" 59 | }, 60 | { 61 | "idiom" : "ipad", 62 | "size" : "29x29", 63 | "scale" : "2x" 64 | }, 65 | { 66 | "idiom" : "ipad", 67 | "size" : "40x40", 68 | "scale" : "1x" 69 | }, 70 | { 71 | "idiom" : "ipad", 72 | "size" : "40x40", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "76x76", 77 | "idiom" : "ipad", 78 | "filename" : "AppIcon-76.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "76x76", 83 | "idiom" : "ipad", 84 | "filename" : "AppIcon-152.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "83.5x83.5", 89 | "idiom" : "ipad", 90 | "filename" : "AppIcon-167.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "1024x1024", 95 | "idiom" : "ios-marketing", 96 | "filename" : "Logo.png", 97 | "scale" : "1x" 98 | } 99 | ], 100 | "info" : { 101 | "version" : 1, 102 | "author" : "xcode" 103 | } 104 | } -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo iOS/Assets.xcassets/AppIcon.appiconset/Logo.png -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewCells/CollectionHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionHeaderView.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 20/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is loaded from a NIB, and is the XIB file's 14 | * root view (and not the File's Owner). => it is `NibLoadable` 15 | * 16 | * It is also reusable and has a `reuseIdentifier` (as it's a CollectionViewCell 17 | * and it uses the CollectionView recycling mechanism) => it is `Reusable` 18 | * 19 | * That's why it's annotated with the `NibReusable` protocol, 20 | * Which in fact is just a convenience typealias that combines 21 | * `NibLoadable` & `Reusable` protocols. 22 | */ 23 | final class CollectionHeaderView: UICollectionReusableView, NibReusable { 24 | @IBOutlet private weak var titleLabel: UILabel! { 25 | didSet { update() } 26 | } 27 | var title: String? { 28 | didSet { update() } 29 | } 30 | private func update() { 31 | titleLabel?.text = title 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewCells/CollectionHeaderView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewCells/MyColorSquareCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyColorSquareCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is reusable and has a `reuseIdentifier` (as it's a CollectionViewCell 14 | * and it uses the Collectioniew recycling mechanism). 15 | * 16 | * That's why it's annotated with the `Reusable` protocol. 17 | * 18 | * This view is NOT loaded from a NIB (but defined entierly by code), 19 | * that's why it's not annotated as `NibLoadable` but only `Reusable` 20 | */ 21 | final class MyColorSquareCell: UICollectionViewCell, Reusable { 22 | private lazy var colorView: UIView = { 23 | let colorView = UIView() 24 | colorView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 25 | colorView.frame = self.contentView.bounds.insetBy(dx: 10, dy: 10) 26 | self.contentView.addSubview(colorView) 27 | return colorView 28 | }() 29 | 30 | func fill(_ color: UIColor) { 31 | self.colorView.backgroundColor = color 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewCells/MyStoryboardTextSquareCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyStoryboardTextSquareCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This one can be either `NibReusable` or just `Reusable` it doesn't really matter, 14 | * as we will never have to explicitly call `collectionView.register(…)` to register it: 15 | * The `Main.storyboard` already auto-registers its cells without the need for additional code 16 | * 17 | * The only difference in marking a view `NibReusable` vs. `Reusable` is the way 18 | * `registerCell` is implemented, and as we won't need to call that method anyway 19 | * because the storyboard will register the cell for us, this makes no difference here. 20 | */ 21 | final class MyStoryboardTextSquareCell: UICollectionViewCell, Reusable { 22 | @IBOutlet private weak var titleLabel: UILabel! 23 | func fill(_ text: String) { 24 | titleLabel.text = text 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewCells/MyXIBIndexSquaceCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyXIBIndexSquaceCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is loaded from a NIB, and is the XIB file's 14 | * root view (and not the File's Owner). => it is `NibLoadable` 15 | * 16 | * It is also reusable and has a `reuseIdentifier` (as it's a CollectionViewCell 17 | * and it uses the CollectionView recycling mechanism) => it is `Reusable` 18 | * 19 | * That's why it's annotated with the `NibReusable` protocol, 20 | * Which in fact is just a typealias that combines 21 | * `NibLoadable` & `Reusable` protocols. 22 | */ 23 | final class MyXIBIndexSquaceCell: UICollectionViewCell, NibReusable { 24 | @IBOutlet private weak var sectionLabel: UILabel! 25 | @IBOutlet private weak var rowLabel: UILabel! 26 | 27 | func fill(_ indexPath: IndexPath) { 28 | sectionLabel.text = String(indexPath.section) 29 | rowLabel.text = String(indexPath.row) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewCells/MyXIBIndexSquaceCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CollectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class CollectionViewController: UICollectionViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | guard let collectionView = self.collectionView else { return } 16 | 17 | // Register cell classes 18 | collectionView.register(cellType: MyColorSquareCell.self) 19 | collectionView.register(cellType: MyXIBIndexSquaceCell.self) 20 | // No need to register this one, the UIStoryboard already auto-register its cells 21 | // self.collectionView.registerReusableCell(MyStoryBoardIndexPathCell) 22 | 23 | collectionView.register(supplementaryViewType: CollectionHeaderView.self, 24 | ofKind: UICollectionView.elementKindSectionHeader) 25 | 26 | if let flowLayout = self.collectionView?.collectionViewLayout as? UICollectionViewFlowLayout { 27 | flowLayout.headerReferenceSize = CGSize(width: collectionView.bounds.size.width, height: 60) 28 | } 29 | } 30 | 31 | // MARK: UICollectionViewDataSource 32 | 33 | override func numberOfSections(in collectionView: UICollectionView) -> Int { 34 | return 3 35 | } 36 | 37 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 38 | return 5 39 | } 40 | 41 | override func collectionView(_ collectionView: UICollectionView, 42 | viewForSupplementaryElementOfKind kind: String, 43 | at indexPath: IndexPath) -> UICollectionReusableView { 44 | let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, for: indexPath) as CollectionHeaderView 45 | header.title = "Section \(indexPath.section)" 46 | return header 47 | } 48 | 49 | override func collectionView(_ collectionView: UICollectionView, 50 | cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 51 | switch indexPath.section { 52 | case 0: 53 | let cell = collectionView.dequeueReusableCell(for: indexPath) as MyColorSquareCell 54 | let red = CGFloat(indexPath.row) / CGFloat(collectionView.numberOfItems(inSection: indexPath.section)) 55 | cell.fill(UIColor(red: red, green: 0.0, blue: 1.0-red, alpha: 1.0)) 56 | return cell 57 | case 1: 58 | let cell = collectionView.dequeueReusableCell(for: indexPath) as MyStoryboardTextSquareCell 59 | cell.fill("Item #\(indexPath.row)") 60 | return cell 61 | case 2: 62 | let cell = collectionView.dequeueReusableCell(for: indexPath) as MyXIBIndexSquaceCell 63 | cell.fill(indexPath) 64 | return cell 65 | default: 66 | fatalError("Out of bounds, should not happen") 67 | } 68 | } 69 | } 70 | 71 | // Swift < 4.2 support 72 | #if !(swift(>=4.2)) 73 | private extension UICollectionView { 74 | static let elementKindSectionHeader = UICollectionElementKindSectionHeader 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CustomViews/MyCustomWidget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyCustomWidget.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier HALLIGON on 18/08/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | class MyCustomWidget: UIView, NibOwnerLoadable { 13 | @IBInspectable var rectColor: UIColor? { 14 | didSet { 15 | self.rectView.backgroundColor = self.rectColor 16 | } 17 | } 18 | @IBInspectable var text: String? { 19 | didSet { 20 | self.textLabel.text = self.text 21 | } 22 | } 23 | 24 | @IBOutlet private var rectView: UIView! 25 | @IBOutlet private var textLabel: UILabel! 26 | 27 | required init?(coder aDecoder: NSCoder) { 28 | super.init(coder: aDecoder) 29 | self.loadNibContent() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/CustomViews/MyCustomWidget.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Storyboards/InfoDetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfoDetailViewController.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 10/07/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | final class InfoDetailViewController: UIViewController, StoryboardSceneBased { 13 | static let sceneStoryboard = UIStoryboard(name: "InfoViewController", bundle: nil) 14 | 15 | @IBOutlet private weak var detailsLabel: UILabel! 16 | private var detailsText: String? 17 | 18 | func setDetails(_ text: String) { 19 | detailsText = text 20 | detailsLabel?.text = text 21 | } 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | detailsLabel.text = detailsText 26 | } 27 | 28 | @IBAction func closeAction(_ sender: UIButton) { 29 | self.presentingViewController?.dismiss(animated: true, completion: nil) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Storyboards/InfoViewController.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 | 31 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 82 | 88 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/Storyboards/InfoViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfoViewController.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 10/07/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | final class InfoViewController: UIViewController, StoryboardBased { 13 | @IBOutlet private weak var infoLabel: UILabel! 14 | private var infoText: String? 15 | 16 | func setInfo(_ text: String) { 17 | infoText = text 18 | infoLabel?.text = text 19 | } 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | infoLabel.text = infoText 24 | } 25 | 26 | @IBAction func closeAction(_ sender: UIButton) { 27 | self.presentingViewController?.dismiss(animated: true, completion: nil) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyHeaderTableViex.swift 3 | // ReusableDemo 4 | // 5 | // Created by Allan Vialatte on 29/05/16. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is loaded from a NIB, and is used as the File's Owner 14 | * of the XIB file (and not set as the XIB's root view) 15 | * 16 | * That's why it's annotated with the `NibOwnerLoadable` protocol. 17 | */ 18 | final class MyHeaderTableView: UIView, NibOwnerLoadable { 19 | 20 | @IBOutlet private weak var titleLabel: UILabel! 21 | static let height: CGFloat = 55 22 | 23 | override init(frame: CGRect) { 24 | super.init(frame: frame) 25 | self.loadNibContent() 26 | } 27 | 28 | required init?(coder aDecoder: NSCoder) { 29 | super.init(coder: aDecoder) 30 | } 31 | 32 | func fillForSection(_ section: Int) { 33 | self.titleLabel.text = "Header Section #\(section)" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MySimpleColorCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MySimpleColorCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is reusable and has a `reuseIdentifier` (as it's a TableViewCell 14 | * and it uses the TableView recycling mechanism). 15 | * 16 | * That's why it's annotated with the `Reusable` protocol. 17 | * 18 | * This view is NOT loaded from a NIB (but defined entierly by code), 19 | * that's why it's not annotated as `NibLoadable` but only `Reusable` 20 | */ 21 | final class MySimpleColorCell: UITableViewCell, Reusable { 22 | private lazy var colorView: UIView = { 23 | let colorView = UIView() 24 | colorView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 25 | colorView.frame = self.contentView.bounds.insetBy(dx: 50, dy: 5) 26 | self.contentView.addSubview(colorView) 27 | return colorView 28 | }() 29 | 30 | func fill(_ color: UIColor) { 31 | self.colorView.backgroundColor = color 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyStoryBoardIndexPathCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyStoryBoardIndexPathCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | // This one can be either `NibReusable` or just `Reusable` it doesn't matter actually 13 | // As we will never have to explicitly call `tableView.register(…)` to register it: 14 | // The Main.storyboard already auto-registers its cells without the need for additional code 15 | 16 | final class MyStoryBoardIndexPathCell: UITableViewCell, Reusable { 17 | @IBOutlet private weak var sectionLabel: UILabel! 18 | @IBOutlet private weak var rowLabel: UILabel! 19 | 20 | func fill(_ indexPath: IndexPath) { 21 | sectionLabel.text = String(indexPath.section) 22 | rowLabel.text = String(indexPath.row) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyXIBInfoCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyXIBSwitchCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is loaded from a NIB, and is the XIB file's 14 | * root view (and not the File's Owner). => it is `NibLoadable` 15 | * 16 | * It is also reusable and has a `reuseIdentifier` (as it's a TableViewCell 17 | * and it uses the TableView recycling mechanism) => it is `Reusable` 18 | * 19 | * That's why it's annotated with the `NibReusable` typealias, 20 | * Which in fact is just a convenience typealias that combines 21 | * `NibLoadable` & `Reusable` protocols. 22 | */ 23 | final class MyXIBInfoCell: UITableViewCell, NibReusable { 24 | 25 | @IBOutlet private weak var titleLabel: UILabel! 26 | private var info: String = "" 27 | private var details: String = "" 28 | 29 | func fill(_ title: String, info: String, details: String) { 30 | self.titleLabel.text = title 31 | self.info = info 32 | self.details = details 33 | } 34 | 35 | @IBAction func infoAction(_ sender: UIButton) { 36 | let infoVC = InfoViewController.instantiate() 37 | infoVC.setInfo(self.info) 38 | self.window?.rootViewController?.present(infoVC, animated: true, completion: nil) 39 | } 40 | 41 | @IBAction func detailsAction(_ sender: UIButton) { 42 | let detailsVC = InfoDetailViewController.instantiate() 43 | detailsVC.setDetails(self.details) 44 | self.window?.rootViewController?.present(detailsVC, animated: true, completion: nil) 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyXIBInfoCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 34 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyXIBTextCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyXIBTextCell.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | /** 13 | * This view is loaded from a NIB, and is the XIB file's 14 | * root view (and not the File's Owner). => it is `NibLoadable` 15 | * 16 | * It is also reusable and has a `reuseIdentifier` (as it's a TableViewCell 17 | * and it uses the TableView recycling mechanism) => it is `Reusable` 18 | * 19 | * That's why it's annotated with the `NibReusable` typealias, 20 | * Which in fact is just a convenience typealias that combines 21 | * `NibLoadable` & `Reusable` protocols. 22 | */ 23 | final class MyXIBTextCell: UITableViewCell, NibReusable { 24 | 25 | @IBOutlet private weak var titleLabel: UILabel! 26 | 27 | func fill(_ text: String) { 28 | titleLabel.text = text 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewCells/MyXIBTextCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/ReusableDemo iOS/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier Halligon on 19/01/2016. 6 | // Copyright © 2016 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class TableViewController: UITableViewController { 12 | var boolValues = [false, false] 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | tableView.register(cellType: MySimpleColorCell.self) 18 | tableView.register(cellType: MyXIBTextCell.self) 19 | tableView.register(cellType: MyXIBInfoCell.self) 20 | 21 | /* No need to register this one, the UIStoryboard already auto-register its cells */ 22 | // tableView.registerReusableCell(MyStoryBoardIndexPathCell) 23 | } 24 | 25 | override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 26 | return MyHeaderTableView.height 27 | } 28 | 29 | override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 30 | let frame = CGRect( 31 | x: 0, 32 | y: 0, 33 | width: tableView.bounds.size.width, 34 | height: self.tableView(tableView, heightForHeaderInSection: section) 35 | ) 36 | // See the overridden `MyHeaderTableView.init(frame:)` initializer, which 37 | // automatically loads the view content from its nib using loadNibContent() 38 | let view = MyHeaderTableView(frame: frame) 39 | 40 | view.fillForSection(section) 41 | return view 42 | } 43 | 44 | override func numberOfSections(in tableView: UITableView) -> Int { 45 | return 4 46 | } 47 | 48 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 49 | return 2 50 | } 51 | 52 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 53 | switch indexPath.section { 54 | case 0: 55 | let colorCell = tableView.dequeueReusableCell(for: indexPath) as MySimpleColorCell 56 | let redComp: CGFloat = indexPath.row == 0 ? 1.0 : 0.0 57 | colorCell.fill(UIColor(red: redComp, green: 0.0, blue: 1-redComp, alpha: 1.0)) 58 | return colorCell 59 | case 1: 60 | let textCell = tableView.dequeueReusableCell(for: indexPath) as MyXIBTextCell 61 | textCell.fill("{section \(indexPath.section), row \(indexPath.row)}") 62 | return textCell 63 | case 2: 64 | let infoCell = tableView.dequeueReusableCell(for: indexPath) as MyXIBInfoCell 65 | infoCell.fill("InfoCell #\(indexPath.row)", info: "Info #\(indexPath.row)", details: "Details #\(indexPath.row)") 66 | return infoCell 67 | case 3: 68 | let pathCell = tableView.dequeueReusableCell(for: indexPath) as MyStoryBoardIndexPathCell 69 | pathCell.fill(indexPath) 70 | return pathCell 71 | default: 72 | fatalError("Out of bounds, should not happen") 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ReusableDemo tvOS 4 | // 5 | // Created by Olivier HALLIGON on 16/02/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, 17 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | } 22 | 23 | // Swift < 4.2 support 24 | #if !(swift(>=4.2)) 25 | extension UIApplication { 26 | typealias LaunchOptionsKey = UIApplicationLaunchOptionsKey 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/AppleTV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/AppleTV.png -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppleTV.png", 5 | "idiom" : "tv", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "tv", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "author" : "xcode", 15 | "version" : 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/AppleTV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/AppleTV.png -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppleTV.png", 5 | "idiom" : "tv", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "tv", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "author" : "xcode", 15 | "version" : 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/AppleTV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/AppleTV.png -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppleTV.png", 5 | "idiom" : "tv", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "tv", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "author" : "xcode", 15 | "version" : 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/AppleTV-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/AppleTV-small.png -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppleTV-small.png", 5 | "idiom" : "tv", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "tv", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "author" : "xcode", 15 | "version" : 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/AppleTV-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/AppleTV-small.png -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppleTV-small.png", 5 | "idiom" : "tv", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "tv", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "author" : "xcode", 15 | "version" : 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "size" : "1280x768", 5 | "idiom" : "tv", 6 | "filename" : "App Icon - Large.imagestack", 7 | "role" : "primary-app-icon" 8 | }, 9 | { 10 | "size" : "400x240", 11 | "idiom" : "tv", 12 | "filename" : "App Icon - Small.imagestack", 13 | "role" : "primary-app-icon" 14 | }, 15 | { 16 | "size" : "2320x720", 17 | "idiom" : "tv", 18 | "filename" : "Top Shelf Image Wide.imageset", 19 | "role" : "top-shelf-image-wide" 20 | }, 21 | { 22 | "size" : "1920x720", 23 | "idiom" : "tv", 24 | "filename" : "Top Shelf Image.imageset", 25 | "role" : "top-shelf-image" 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | } 32 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "tv", 6 | "minimum-system-version" : "11.0", 7 | "orientation" : "landscape", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "extent" : "full-screen", 12 | "idiom" : "tv", 13 | "minimum-system-version" : "9.0", 14 | "orientation" : "landscape", 15 | "scale" : "1x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIMainStoryboardFile 24 | Main 25 | UIRequiredDeviceCapabilities 26 | 27 | arm64 28 | 29 | UIUserInterfaceStyle 30 | Automatic 31 | 32 | 33 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/MyCustomWidget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyCustomWidget.swift 3 | // ReusableDemo 4 | // 5 | // Created by Olivier HALLIGON on 16/02/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Reusable 11 | 12 | class MyCustomWidget: UIView, NibOwnerLoadable { 13 | @IBInspectable var rectColor: UIColor? { 14 | didSet { 15 | self.rectView.backgroundColor = self.rectColor 16 | } 17 | } 18 | @IBInspectable var text: String? { 19 | didSet { 20 | self.textLabel.text = self.text 21 | } 22 | } 23 | 24 | @IBOutlet private var rectView: UIView! 25 | @IBOutlet private var textLabel: UILabel! 26 | 27 | required init?(coder aDecoder: NSCoder) { 28 | super.init(coder: aDecoder) 29 | self.loadNibContent() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Example/ReusableDemo tvOS/MyCustomWidget.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Example/ReusableDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/ReusableDemo.xcodeproj/xcshareddata/xcschemes/ReusableDemo iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Example/ReusableDemo.xcodeproj/xcshareddata/xcschemes/ReusableDemo tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Example/ReusableDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 17 | 19 | 20 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Example/ReusableDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/ReusableDemo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | # The bare minimum for building, e.g. in Homebrew 6 | group :build do 7 | gem 'rake', '~> 12.3' 8 | gem 'xcpretty' 9 | end 10 | 11 | # In addition to :build, for contributing 12 | group :development do 13 | gem 'cocoapods', '~> 1.8' 14 | end 15 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.3) 5 | activesupport (6.1.4.1) 6 | concurrent-ruby (~> 1.0, >= 1.0.2) 7 | i18n (>= 1.6, < 2) 8 | minitest (>= 5.1) 9 | tzinfo (~> 2.0) 10 | zeitwerk (~> 2.3) 11 | addressable (2.8.0) 12 | public_suffix (>= 2.0.2, < 5.0) 13 | algoliasearch (1.27.5) 14 | httpclient (~> 2.8, >= 2.8.3) 15 | json (>= 1.5.1) 16 | atomos (0.1.3) 17 | claide (1.0.3) 18 | cocoapods (1.11.0) 19 | addressable (~> 2.8) 20 | claide (>= 1.0.2, < 2.0) 21 | cocoapods-core (= 1.11.0) 22 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 23 | cocoapods-downloader (>= 1.4.0, < 2.0) 24 | cocoapods-plugins (>= 1.0.0, < 2.0) 25 | cocoapods-search (>= 1.0.0, < 2.0) 26 | cocoapods-trunk (>= 1.4.0, < 2.0) 27 | cocoapods-try (>= 1.1.0, < 2.0) 28 | colored2 (~> 3.1) 29 | escape (~> 0.0.4) 30 | fourflusher (>= 2.3.0, < 3.0) 31 | gh_inspector (~> 1.0) 32 | molinillo (~> 0.8.0) 33 | nap (~> 1.0) 34 | ruby-macho (>= 1.0, < 3.0) 35 | xcodeproj (>= 1.21.0, < 2.0) 36 | cocoapods-core (1.11.0) 37 | activesupport (>= 5.0, < 7) 38 | addressable (~> 2.8) 39 | algoliasearch (~> 1.0) 40 | concurrent-ruby (~> 1.1) 41 | fuzzy_match (~> 2.0.4) 42 | nap (~> 1.0) 43 | netrc (~> 0.11) 44 | public_suffix (~> 4.0) 45 | typhoeus (~> 1.0) 46 | cocoapods-deintegrate (1.0.5) 47 | cocoapods-downloader (1.5.1) 48 | cocoapods-plugins (1.0.0) 49 | nap 50 | cocoapods-search (1.0.1) 51 | cocoapods-trunk (1.6.0) 52 | nap (>= 0.8, < 2.0) 53 | netrc (~> 0.11) 54 | cocoapods-try (1.2.0) 55 | colored2 (3.1.2) 56 | concurrent-ruby (1.1.9) 57 | escape (0.0.4) 58 | ethon (0.14.0) 59 | ffi (>= 1.15.0) 60 | ffi (1.15.4) 61 | fourflusher (2.3.1) 62 | fuzzy_match (2.0.4) 63 | gh_inspector (1.1.3) 64 | httpclient (2.8.3) 65 | i18n (1.8.10) 66 | concurrent-ruby (~> 1.0) 67 | json (2.5.1) 68 | minitest (5.14.4) 69 | molinillo (0.8.0) 70 | nanaimo (0.3.0) 71 | nap (1.1.0) 72 | netrc (0.11.0) 73 | public_suffix (4.0.6) 74 | rake (12.3.3) 75 | rexml (3.2.5) 76 | rouge (2.0.7) 77 | ruby-macho (2.5.1) 78 | typhoeus (1.4.0) 79 | ethon (>= 0.9.0) 80 | tzinfo (2.0.4) 81 | concurrent-ruby (~> 1.0) 82 | xcodeproj (1.21.0) 83 | CFPropertyList (>= 2.3.3, < 4.0) 84 | atomos (~> 0.1.3) 85 | claide (>= 1.0.2, < 2.0) 86 | colored2 (~> 3.1) 87 | nanaimo (~> 0.3.0) 88 | rexml (~> 3.2.4) 89 | xcpretty (0.3.0) 90 | rouge (~> 2.0.7) 91 | zeitwerk (2.4.2) 92 | 93 | PLATFORMS 94 | ruby 95 | 96 | DEPENDENCIES 97 | cocoapods (~> 1.8) 98 | rake (~> 12.3) 99 | xcpretty 100 | 101 | BUNDLED WITH 102 | 2.2.25 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 AliSoftware 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Logo.png -------------------------------------------------------------------------------- /Logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/Logo.xcf -------------------------------------------------------------------------------- /NibOwnerLoadable-InStoryboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/NibOwnerLoadable-InStoryboard.png -------------------------------------------------------------------------------- /NibOwnerLoadable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliSoftware/Reusable/85e8ef7b2441433ffed2fc8cf4942961b70a83f6/NibOwnerLoadable.png -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.4 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "Reusable", 6 | platforms: [.iOS(.v9), .tvOS(.v9)], 7 | products: [ 8 | .library(name: "Reusable", targets: ["Reusable"]) 9 | ], 10 | targets: [ 11 | .target( 12 | name: "Reusable", 13 | path: "Sources" 14 | ) 15 | ], 16 | swiftLanguageVersions: [.v4, .v5] 17 | ) 18 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/rake 2 | 3 | DESTINATIONS = { 4 | :ios_sim => "OS=14.5,name=iPhone 11,platform=iOS Simulator", 5 | :tvos_sim => "OS=14.5,name=Apple TV,platform=tvOS Simulator", 6 | } 7 | 8 | CARTHAGE_VERSION = '0.38.0' 9 | SWIFTLINT_VERSION = '0.44.0' 10 | 11 | ## UTILS ## 12 | 13 | def run(command, xcpretty: true) 14 | if xcpretty && system('xcpretty --version >/dev/null') 15 | sh "set -o pipefail && #{command} | xcpretty -c" 16 | else 17 | sh command 18 | end 19 | end 20 | 21 | def xcodebuild(scheme: '', sdk: '', destination: '', action: 'build') 22 | run %Q(xcodebuild -workspace Example/ReusableDemo.xcworkspace -scheme "#{scheme}" -sdk #{sdk} -destination="#{destination}" ONLY_ACTIVE_ARCH=NO #{action}) 23 | end 24 | 25 | def install_pkg(pkg_url) 26 | require 'tmpdir' 27 | Dir.mktmpdir do |dir| 28 | tmppath = File.join(dir, File.basename(pkg_url)) 29 | sh("curl -Lo #{tmppath} #{pkg_url}") 30 | sh("sudo installer -pkg #{tmppath} -target /") 31 | end 32 | end 33 | 34 | ## TASKS ## 35 | 36 | namespace :carthage do 37 | desc "Install Carthage from pkg" 38 | task :install do 39 | next if system('which carthage >/dev/null') && Gem::Version.new(`carthage version`.chomp) >= Gem::Version.new(CARTHAGE_VERSION) 40 | install_pkg("https://github.com/Carthage/Carthage/releases/download/#{CARTHAGE_VERSION}/Carthage.pkg") 41 | end 42 | 43 | desc "Builds the Reusable framework using Carthage" 44 | task :build => :install do 45 | run "carthage build --no-skip-current --use-xcframeworks --verbose" 46 | end 47 | end 48 | 49 | namespace :demo do 50 | desc "Builds the ReusableDemo app for iOS using xcodebuild." 51 | task :ios do |t, args| 52 | xcodebuild(scheme: 'ReusableDemo iOS', sdk: 'iphonesimulator', destination: DESTINATIONS[:ios_sim]) 53 | end 54 | 55 | desc "Builds the ReusableDemo app for tvOS using xcodebuild." 56 | task :tvos do |t, args| 57 | xcodebuild(scheme: 'ReusableDemo tvOS', sdk: 'appletvsimulator', destination: DESTINATIONS[:tvos_sim]) 58 | end 59 | end 60 | 61 | namespace :fmk do 62 | desc "Builds the Reusable framework for iOS using xcodebuild." 63 | task :ios do |t, args| 64 | xcodebuild(scheme: 'Reusable-iOS', sdk: 'iphonesimulator', destination: DESTINATIONS[:ios_sim]) 65 | end 66 | 67 | desc "Builds the Reusable framework for tvOS using xcodebuild." 68 | task :tvos do |t, args| 69 | xcodebuild(scheme: 'Reusable-tvOS', sdk: 'appletvsimulator', destination: DESTINATIONS[:tvos_sim]) 70 | end 71 | end 72 | 73 | namespace :pod do 74 | desc "Lints the Reusable.podspec" 75 | task :lint do |t| 76 | run("pod lib lint --allow-warnings --quick", xcpretty: false) 77 | end 78 | end 79 | 80 | namespace :spm do 81 | desc 'Build using SPM' 82 | task :build do |task| 83 | puts '*** Compile using SPM ***' 84 | sh 'xcrun swift build' 85 | end 86 | end 87 | 88 | namespace :swiftlint do 89 | desc "Install SwiftLint from pkg" 90 | task :install do 91 | next if system('which swiftlint >/dev/null') && Gem::Version.new(`swiftlint version`.chomp) >= Gem::Version.new(SWIFTLINT_VERSION) 92 | install_pkg("https://github.com/realm/SwiftLint/releases/download/#{SWIFTLINT_VERSION}/SwiftLint.pkg") 93 | end 94 | 95 | desc "Run SwiftLint on the source code" 96 | task :run => :install do 97 | run('swiftlint lint --strict', xcpretty: false) 98 | end 99 | end 100 | 101 | # TODO: "namespace :test" once we have Unit Tests 102 | -------------------------------------------------------------------------------- /Reusable.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.cocoapods_version = '~> 1.4' 3 | 4 | s.name = "Reusable" 5 | s.version = "4.1.2" 6 | s.summary = "A Swift Mixin to deal with reusable UITableView & UICollectionView cells and XIB-based views" 7 | 8 | s.description = <<-DESC 9 | Reusable is a [Swift Mixin](http://alisoftware.github.io/swift/protocol/2015/11/08/mixins-over-inheritance/) 10 | to easily deal with your reusable UITableViewCell and UICollectionViewCell classes. 11 | 12 | Simply mark your `UITableViewCell` or `UICollectionViewCell` sublcasses as 13 | conforming to either `Reusable` or `NibReusable` and you'll be able to 14 | manipulate them way easier, and without worrying with String-type reuseIdentifiers 15 | ever again, and instead use them in a type-safe manner! 16 | 17 | Reusable also support marking any arbitrary `UIView` subclass as `NibLoadable` so that 18 | you can then call `loadFromNib()` on the custom view class easily without adding any code. 19 | 20 | For more info, see [my blog post](http://alisoftware.github.io/swift/generics/2016/01/06/generic-tableviewcells/) 21 | about this technique. 22 | DESC 23 | 24 | s.homepage = "https://github.com/AliSoftware/Reusable" 25 | s.license = { :type => "MIT", :file => "LICENSE" } 26 | 27 | 28 | s.author = { "Olivier Halligon" => "olivier@halligon.net" } 29 | s.social_media_url = "http://twitter.com/aligatr" 30 | 31 | s.ios.deployment_target = "9.0" 32 | s.tvos.deployment_target = "9.0" 33 | 34 | s.source = { :git => "https://github.com/AliSoftware/Reusable.git", :tag => s.version.to_s } 35 | s.swift_version = '5.0' 36 | 37 | s.subspec 'View' do |ss| 38 | ss.source_files = "Sources/View/*.swift" 39 | end 40 | s.subspec 'Storyboard' do |ss| 41 | ss.source_files = "Sources/Storyboard/*.swift" 42 | end 43 | 44 | s.framework = "UIKit" 45 | 46 | end 47 | -------------------------------------------------------------------------------- /Sources/Storyboard/StoryboardBased.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Protocol Definition 13 | 14 | /// Make your UIViewController subclasses conform to this protocol when: 15 | /// * they *are* Storyboard-based, and 16 | /// * this ViewController is the initialViewController of your Storyboard 17 | /// 18 | /// to be able to instantiate them from the Storyboard in a type-safe manner 19 | public protocol StoryboardBased: AnyObject { 20 | /// The UIStoryboard to use when we want to instantiate this ViewController 21 | static var sceneStoryboard: UIStoryboard { get } 22 | } 23 | 24 | // MARK: Default Implementation 25 | 26 | public extension StoryboardBased { 27 | /// By default, use the storybaord with the same name as the class 28 | static var sceneStoryboard: UIStoryboard { 29 | return UIStoryboard(name: String(describing: self), bundle: Bundle(for: self)) 30 | } 31 | } 32 | 33 | // MARK: Support for instantiation from Storyboard 34 | 35 | public extension StoryboardBased where Self: UIViewController { 36 | /** 37 | Create an instance of the ViewController from its associated Storyboard's initialViewController 38 | 39 | - returns: instance of the conforming ViewController 40 | */ 41 | static func instantiate() -> Self { 42 | let viewController = sceneStoryboard.instantiateInitialViewController() 43 | guard let typedViewController = viewController as? Self else { 44 | fatalError("The initialViewController of '\(sceneStoryboard)' is not of class '\(self)'") 45 | } 46 | return typedViewController 47 | } 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /Sources/Storyboard/StoryboardSceneBased.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Protocol Definition 13 | 14 | /// Make your UIViewController subclasses conform to this protocol when: 15 | /// * they *are* Storyboard-based, and 16 | /// * this ViewController is not the initialViewController of your Storyboard, but a different scene 17 | /// 18 | /// to be able to instantiate them from the Storyboard in a type-safe manner. 19 | /// 20 | /// You need to implement `sceneStoryboard` yourself to indicate the UIStoryboard this scene is from. 21 | public protocol StoryboardSceneBased: AnyObject { 22 | /// The UIStoryboard to use when we want to instantiate this ViewController 23 | static var sceneStoryboard: UIStoryboard { get } 24 | /// The scene identifier to use when we want to instantiate this ViewController from its associated Storyboard 25 | static var sceneIdentifier: String { get } 26 | } 27 | 28 | // MARK: Default Implementation 29 | 30 | public extension StoryboardSceneBased { 31 | /// By default, use the `sceneIdentifier` with the same name as the class 32 | static var sceneIdentifier: String { 33 | return String(describing: self) 34 | } 35 | } 36 | 37 | // MARK: Support for instantiation from Storyboard 38 | 39 | public extension StoryboardSceneBased where Self: UIViewController { 40 | /** 41 | Create an instance of the ViewController from its associated Storyboard and the 42 | Scene with identifier `sceneIdentifier` 43 | 44 | - returns: instance of the conforming ViewController 45 | */ 46 | static func instantiate() -> Self { 47 | let storyboard = Self.sceneStoryboard 48 | let viewController = storyboard.instantiateViewController(withIdentifier: self.sceneIdentifier) 49 | guard let typedViewController = viewController as? Self else { 50 | fatalError("The viewController '\(self.sceneIdentifier)' of '\(storyboard)' is not of class '\(self)'") 51 | } 52 | return typedViewController 53 | } 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /Sources/View/NibLoadable.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Protocol Definition 13 | 14 | /// Make your UIView subclasses conform to this protocol when: 15 | /// * they *are* NIB-based, and 16 | /// * this class is used as the XIB's root view 17 | /// 18 | /// to be able to instantiate them from the NIB in a type-safe manner 19 | public protocol NibLoadable: AnyObject { 20 | /// The nib file to use to load a new instance of the View designed in a XIB 21 | static var nib: UINib { get } 22 | } 23 | 24 | // MARK: Default implementation 25 | 26 | public extension NibLoadable { 27 | /// By default, use the nib which have the same name as the name of the class, 28 | /// and located in the bundle of that class 29 | static var nib: UINib { 30 | return UINib(nibName: String(describing: self), bundle: Bundle(for: self)) 31 | } 32 | } 33 | 34 | // MARK: Support for instantiation from NIB 35 | 36 | public extension NibLoadable where Self: UIView { 37 | /** 38 | Returns a `UIView` object instantiated from nib 39 | 40 | - returns: A `NibLoadable`, `UIView` instance 41 | */ 42 | static func loadFromNib() -> Self { 43 | guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else { 44 | fatalError("The nib \(nib) expected its root view to be of type \(self)") 45 | } 46 | return view 47 | } 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /Sources/View/NibOwnerLoadable.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Protocol Definition 13 | 14 | /// Make your UIView subclasses conform to this protocol when: 15 | /// * they *are* NIB-based, and 16 | /// * this class is used as the XIB's File's Owner 17 | /// 18 | /// to be able to instantiate them from the NIB in a type-safe manner 19 | public protocol NibOwnerLoadable: AnyObject { 20 | /// The nib file to use to load a new instance of the View designed in a XIB 21 | static var nib: UINib { get } 22 | } 23 | 24 | // MARK: Default implementation 25 | 26 | public extension NibOwnerLoadable { 27 | /// By default, use the nib which have the same name as the name of the class, 28 | /// and located in the bundle of that class 29 | static var nib: UINib { 30 | return UINib(nibName: String(describing: self), bundle: Bundle(for: self)) 31 | } 32 | } 33 | 34 | // MARK: Support for instantiation from NIB 35 | 36 | public extension NibOwnerLoadable where Self: UIView { 37 | /** 38 | Adds content loaded from the nib to the end of the receiver's list of subviews and adds constraints automatically. 39 | */ 40 | func loadNibContent() { 41 | let layoutAttributes: [NSLayoutConstraint.Attribute] = [.top, .leading, .bottom, .trailing] 42 | for case let view as UIView in type(of: self).nib.instantiate(withOwner: self, options: nil) { 43 | view.translatesAutoresizingMaskIntoConstraints = false 44 | self.addSubview(view) 45 | NSLayoutConstraint.activate(layoutAttributes.map { attribute in 46 | NSLayoutConstraint( 47 | item: view, attribute: attribute, 48 | relatedBy: .equal, 49 | toItem: self, attribute: attribute, 50 | multiplier: 1, constant: 0.0 51 | ) 52 | }) 53 | } 54 | } 55 | } 56 | #endif 57 | 58 | /// Swift < 4.2 support 59 | #if !(swift(>=4.2)) 60 | private extension NSLayoutConstraint { 61 | typealias Attribute = NSLayoutAttribute 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /Sources/View/Reusable.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Protocol definition 13 | 14 | /// Make your `UITableViewCell` and `UICollectionViewCell` subclasses 15 | /// conform to this protocol when they are *not* NIB-based but only code-based 16 | /// to be able to dequeue them in a type-safe manner 17 | public protocol Reusable: AnyObject { 18 | /// The reuse identifier to use when registering and later dequeuing a reusable cell 19 | static var reuseIdentifier: String { get } 20 | } 21 | 22 | /// Make your `UITableViewCell` and `UICollectionViewCell` subclasses 23 | /// conform to this typealias when they *are* NIB-based 24 | /// to be able to dequeue them in a type-safe manner 25 | public typealias NibReusable = Reusable & NibLoadable 26 | 27 | // MARK: - Default implementation 28 | 29 | public extension Reusable { 30 | /// By default, use the name of the class as String for its reuseIdentifier 31 | static var reuseIdentifier: String { 32 | return String(describing: self) 33 | } 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /Sources/View/UICollectionView+Reusable.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Reusable support for UICollectionView 13 | 14 | public extension UICollectionView { 15 | /** 16 | Register a NIB-Based `UICollectionViewCell` subclass (conforming to `Reusable` & `NibLoadable`) 17 | 18 | - parameter cellType: the `UICollectionViewCell` (`Reusable` & `NibLoadable`-conforming) subclass to register 19 | 20 | - seealso: `register(_:,forCellWithReuseIdentifier:)` 21 | */ 22 | final func register(cellType: T.Type) 23 | where T: Reusable & NibLoadable { 24 | self.register(cellType.nib, forCellWithReuseIdentifier: cellType.reuseIdentifier) 25 | } 26 | 27 | /** 28 | Register a Class-Based `UICollectionViewCell` subclass (conforming to `Reusable`) 29 | 30 | - parameter cellType: the `UICollectionViewCell` (`Reusable`-conforming) subclass to register 31 | 32 | - seealso: `register(_:,forCellWithReuseIdentifier:)` 33 | */ 34 | final func register(cellType: T.Type) 35 | where T: Reusable { 36 | self.register(cellType.self, forCellWithReuseIdentifier: cellType.reuseIdentifier) 37 | } 38 | 39 | /** 40 | Returns a reusable `UICollectionViewCell` object for the class inferred by the return-type 41 | 42 | - parameter indexPath: The index path specifying the location of the cell. 43 | - parameter cellType: The cell class to dequeue 44 | 45 | - returns: A `Reusable`, `UICollectionViewCell` instance 46 | 47 | - note: The `cellType` parameter can generally be omitted and infered by the return type, 48 | except when your type is in a variable and cannot be determined at compile time. 49 | - seealso: `dequeueReusableCell(withReuseIdentifier:,for:)` 50 | */ 51 | final func dequeueReusableCell(for indexPath: IndexPath, cellType: T.Type = T.self) -> T 52 | where T: Reusable { 53 | let bareCell = self.dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) 54 | guard let cell = bareCell as? T else { 55 | fatalError( 56 | "Failed to dequeue a cell with identifier \(cellType.reuseIdentifier) matching type \(cellType.self). " 57 | + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " 58 | + "and that you registered the cell beforehand" 59 | ) 60 | } 61 | return cell 62 | } 63 | 64 | /** 65 | Register a NIB-Based `UICollectionReusableView` subclass (conforming to `Reusable` & `NibLoadable`) 66 | as a Supplementary View 67 | 68 | - parameter supplementaryViewType: the `UIView` (`Reusable` & `NibLoadable`-conforming) subclass 69 | to register as Supplementary View 70 | - parameter elementKind: The kind of supplementary view to create. 71 | 72 | - seealso: `register(_:,forSupplementaryViewOfKind:,withReuseIdentifier:)` 73 | */ 74 | final func register(supplementaryViewType: T.Type, ofKind elementKind: String) 75 | where T: Reusable & NibLoadable { 76 | self.register( 77 | supplementaryViewType.nib, 78 | forSupplementaryViewOfKind: elementKind, 79 | withReuseIdentifier: supplementaryViewType.reuseIdentifier 80 | ) 81 | } 82 | 83 | /** 84 | Register a Class-Based `UICollectionReusableView` subclass (conforming to `Reusable`) as a Supplementary View 85 | 86 | - parameter supplementaryViewType: the `UIView` (`Reusable`-conforming) subclass to register as Supplementary View 87 | - parameter elementKind: The kind of supplementary view to create. 88 | 89 | - seealso: `register(_:,forSupplementaryViewOfKind:,withReuseIdentifier:)` 90 | */ 91 | final func register(supplementaryViewType: T.Type, ofKind elementKind: String) 92 | where T: Reusable { 93 | self.register( 94 | supplementaryViewType.self, 95 | forSupplementaryViewOfKind: elementKind, 96 | withReuseIdentifier: supplementaryViewType.reuseIdentifier 97 | ) 98 | } 99 | 100 | /** 101 | Returns a reusable `UICollectionReusableView` object for the class inferred by the return-type 102 | 103 | - parameter elementKind: The kind of supplementary view to retrieve. 104 | - parameter indexPath: The index path specifying the location of the cell. 105 | - parameter viewType: The view class to dequeue 106 | 107 | - returns: A `Reusable`, `UICollectionReusableView` instance 108 | 109 | - note: The `viewType` parameter can generally be omitted and infered by the return type, 110 | except when your type is in a variable and cannot be determined at compile time. 111 | - seealso: `dequeueReusableSupplementaryView(ofKind:,withReuseIdentifier:,for:)` 112 | */ 113 | final func dequeueReusableSupplementaryView 114 | (ofKind elementKind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T 115 | where T: Reusable { 116 | let view = self.dequeueReusableSupplementaryView( 117 | ofKind: elementKind, 118 | withReuseIdentifier: viewType.reuseIdentifier, 119 | for: indexPath 120 | ) 121 | guard let typedView = view as? T else { 122 | fatalError( 123 | "Failed to dequeue a supplementary view with identifier \(viewType.reuseIdentifier) " 124 | + "matching type \(viewType.self). " 125 | + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " 126 | + "and that you registered the supplementary view beforehand" 127 | ) 128 | } 129 | return typedView 130 | } 131 | } 132 | #endif 133 | -------------------------------------------------------------------------------- /Sources/View/UITableView+Reusable.swift: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * This code is under the MIT License (MIT) 4 | * 5 | * Copyright (c) 2016 AliSoftware 6 | * 7 | *********************************************/ 8 | 9 | #if canImport(UIKit) 10 | import UIKit 11 | 12 | // MARK: Reusable support for UITableView 13 | 14 | public extension UITableView { 15 | /** 16 | Register a NIB-Based `UITableViewCell` subclass (conforming to `Reusable` & `NibLoadable`) 17 | 18 | - parameter cellType: the `UITableViewCell` (`Reusable` & `NibLoadable`-conforming) subclass to register 19 | 20 | - seealso: `register(_:,forCellReuseIdentifier:)` 21 | */ 22 | final func register(cellType: T.Type) 23 | where T: Reusable & NibLoadable { 24 | self.register(cellType.nib, forCellReuseIdentifier: cellType.reuseIdentifier) 25 | } 26 | 27 | /** 28 | Register a Class-Based `UITableViewCell` subclass (conforming to `Reusable`) 29 | 30 | - parameter cellType: the `UITableViewCell` (`Reusable`-conforming) subclass to register 31 | 32 | - seealso: `register(_:,forCellReuseIdentifier:)` 33 | */ 34 | final func register(cellType: T.Type) 35 | where T: Reusable { 36 | self.register(cellType.self, forCellReuseIdentifier: cellType.reuseIdentifier) 37 | } 38 | 39 | /** 40 | Returns a reusable `UITableViewCell` object for the class inferred by the return-type 41 | 42 | - parameter indexPath: The index path specifying the location of the cell. 43 | - parameter cellType: The cell class to dequeue 44 | 45 | - returns: A `Reusable`, `UITableViewCell` instance 46 | 47 | - note: The `cellType` parameter can generally be omitted and infered by the return type, 48 | except when your type is in a variable and cannot be determined at compile time. 49 | - seealso: `dequeueReusableCell(withIdentifier:,for:)` 50 | */ 51 | final func dequeueReusableCell(for indexPath: IndexPath, cellType: T.Type = T.self) -> T 52 | where T: Reusable { 53 | guard let cell = self.dequeueReusableCell(withIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { 54 | fatalError( 55 | "Failed to dequeue a cell with identifier \(cellType.reuseIdentifier) matching type \(cellType.self). " 56 | + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " 57 | + "and that you registered the cell beforehand" 58 | ) 59 | } 60 | return cell 61 | } 62 | 63 | /** 64 | Register a NIB-Based `UITableViewHeaderFooterView` subclass (conforming to `Reusable` & `NibLoadable`) 65 | 66 | - parameter headerFooterViewType: the `UITableViewHeaderFooterView` (`Reusable` & `NibLoadable`-conforming) 67 | subclass to register 68 | 69 | - seealso: `register(_:,forHeaderFooterViewReuseIdentifier:)` 70 | */ 71 | final func register(headerFooterViewType: T.Type) 72 | where T: Reusable & NibLoadable { 73 | self.register(headerFooterViewType.nib, forHeaderFooterViewReuseIdentifier: headerFooterViewType.reuseIdentifier) 74 | } 75 | 76 | /** 77 | Register a Class-Based `UITableViewHeaderFooterView` subclass (conforming to `Reusable`) 78 | 79 | - parameter headerFooterViewType: the `UITableViewHeaderFooterView` (`Reusable`-confirming) subclass to register 80 | 81 | - seealso: `register(_:,forHeaderFooterViewReuseIdentifier:)` 82 | */ 83 | final func register(headerFooterViewType: T.Type) 84 | where T: Reusable { 85 | self.register(headerFooterViewType.self, forHeaderFooterViewReuseIdentifier: headerFooterViewType.reuseIdentifier) 86 | } 87 | 88 | /** 89 | Returns a reusable `UITableViewHeaderFooterView` object for the class inferred by the return-type 90 | 91 | - parameter viewType: The view class to dequeue 92 | 93 | - returns: A `Reusable`, `UITableViewHeaderFooterView` instance 94 | 95 | - note: The `viewType` parameter can generally be omitted and infered by the return type, 96 | except when your type is in a variable and cannot be determined at compile time. 97 | - seealso: `dequeueReusableHeaderFooterView(withIdentifier:)` 98 | */ 99 | final func dequeueReusableHeaderFooterView(_ viewType: T.Type = T.self) -> T? 100 | where T: Reusable { 101 | guard let view = self.dequeueReusableHeaderFooterView(withIdentifier: viewType.reuseIdentifier) as? T? else { 102 | fatalError( 103 | "Failed to dequeue a header/footer with identifier \(viewType.reuseIdentifier) " 104 | + "matching type \(viewType.self). " 105 | + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " 106 | + "and that you registered the header/footer beforehand" 107 | ) 108 | } 109 | return view 110 | } 111 | } 112 | #endif 113 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------