[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7035":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":27,"discoverSource":28},7035,"Reusable","AliSoftware\u002FReusable","AliSoftware","A Swift mixin for reusing views easily and in a type-safe way (UITableViewCells, UICollectionViewCells, custom UIViews, ViewControllers, Storyboards…)","",null,"Swift",2986,234,47,15,0,2,59.31,"MIT License",false,"main",true,[],"2026-06-12 04:00:32","# Reusable\n\n\u003Cp align=\"center\">\n  \u003Cimg alt=\"Reusable\" src=\"Logo.png\" width=\"150\" height=\"150\"\u002F>\n\u003C\u002Fp>\n\nA Swift mixin to use `UITableViewCells`, `UICollectionViewCells` and `UIViewControllers` in a **type-safe way**, without the need to manipulate their `String`-typed `reuseIdentifiers`. This library also supports arbitrary `UIView` to be loaded via a XIB using a simple call to `loadFromNib()`\n\n[![CircleCI](https:\u002F\u002Fcircleci.com\u002Fgh\u002FAliSoftware\u002FReusable\u002Ftree\u002Fmaster.svg?style=svg)](https:\u002F\u002Fcircleci.com\u002Fgh\u002FAliSoftware\u002FReusable\u002Ftree\u002Fmaster)\n[![Platform](http:\u002F\u002Fcocoapod-badges.herokuapp.com\u002Fp\u002FReusable\u002Fbadge.png)](http:\u002F\u002Fcocoadocs.org\u002Fdocsets\u002FReusable)\n[![Version](http:\u002F\u002Fcocoapod-badges.herokuapp.com\u002Fv\u002FReusable\u002Fbadge.png)](http:\u002F\u002Fcocoadocs.org\u002Fdocsets\u002FReusable)\n[![Language: Swift 3](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwift-3-orange)](https:\u002F\u002Fswift.org)\n[![Language: Swift 4](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwift-4-orange)](https:\u002F\u002Fswift.org)\n[![Language: Swift 5](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwift-5-orange)](https:\u002F\u002Fswift.org)\n\n# Installation\n\n\u003Cdetails>\u003Csummary>\u003Cb>Requirements\u003C\u002Fb>: which Reusable version to use for each Swift Version?\u003C\u002Fsummary>\n\n|  Swift Version |  Reusable Version  |\n|----------------|--------------------|\n|    2.2 & 2.3   |        2.5.1       |\n|       3.0 (†)  |        3.0.0 +     |\n|       4.0      |        4.0.2 +     |\n|       5.0      |        4.1.0 +     |\n\n_(†) The Reusable 3.0 code also compiles with Swift 4, you'll need 4.0.2+ only if you're using Carthage for integration_\n\n\u003C\u002Fdetails>\n\nReusable can be integrated to your Xcode projects using one of the following options:\n\n\u003Cdetails>\u003Csummary>Installation instructions for \u003Cb>Swift Package Manager (SPM)\u003C\u002Fb>\u003C\u002Fsummary>\n\n[Swift Package Manager](https:\u002F\u002Fswift.org\u002Fpackage-manager\u002F) is Apple's decentralized dependency manager to integrate libraries to your Swift projects. It is now fully integrated with Xcode 11\n\nTo integrate Reusable into your project using SPM, specify it in your `Package.swift` file:\n\n```swift\nlet package = Package(\n    …\n    dependencies: [\n        .package(url: \"https:\u002F\u002Fgithub.com\u002FAliSoftware\u002FReusable.git\", from: \"4.1.0\"),\n    ],\n    targets: [\n        .target(name: \"YourTarget\", dependencies: [\"Reusable\", …])\n        …\n    ]\n)\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\u003Csummary>Installation instructions for \u003Cb>Carthage\u003C\u002Fb>\u003C\u002Fsummary>\n\n[Carthage](https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage) is a decentralized dependency manager to add pre-built frameworks to your Cocoa application.\n\nTo integrate Reusable into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```bash\ngithub \"AliSoftware\u002FReusable\"\n```\n\nThen run `carthage update --use-xcframeworks`\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\u003Csummary>Installation instructions for \u003Cb>CocoaPods\u003C\u002Fb>\u003C\u002Fsummary>\n\n[CocoaPods](https:\u002F\u002Fcocoapods.org\u002F) is a dependency manager to automate integration of frameworks to your Swift and Objective-C Cocoa projects.\n\nTo integrate Reusable into your Xcode project using Cocoapods, specify it in your `Podfile`:\n\n```bash\npod 'Reusable'\n```\n\n\u003C\u002Fdetails>\n\n# Introduction\n\nThis library aims to make it super-easy to create, dequeue and instantiate reusable views anywhere this pattern is used: from the obvious `UITableViewCell` and `UICollectionViewCell` to custom `UIViews`, even supporting `UIViewControllers` from Storyboards.  \nAll of that simply by **marking your classes as conforming to a protocol, without having to add any code**, and **creating a type-safe API with no more String-based API**.\n\n```swift\n\u002F\u002F Example of what Reusable allows you to do\nfinal class MyCustomCell: UITableViewCell, Reusable { \u002F* And that's it! *\u002F }\ntableView.register(cellType: MyCustomCell.self)\nlet cell: MyCustomCell = tableView.dequeueReusableCell(for: indexPath)\n```\n\nThis concept, called a [Mixin](http:\u002F\u002Falisoftware.github.io\u002Fswift\u002Fprotocol\u002F2015\u002F11\u002F08\u002Fmixins-over-inheritance\u002F) (a protocol with default implementation for all its methods), is explained [here in my blog post](http:\u002F\u002Falisoftware.github.io\u002Fswift\u002Fgenerics\u002F2016\u002F01\u002F06\u002Fgeneric-tableviewcells\u002F) in details.\n\n**Table of Contents**\n\n* [Type-safe cells](#type-safe-uitableviewcell--uicollectionviewcell)\n* [Type-safe XIB-based reusable views](#type-safe-xib-based-reusable-views)\n* [Type-safe ViewControllers from Storyboards](#type-safe-viewcontrollers-from-storyboards)\n* [Additional tips](#additional-tips)\n* [Example project](#example-project)\n* [Talks and Articles about Reusable](#talks-and-articles-about-reusable)\n* [License](#license)\n\n\n---\n\n\n\n# Type-safe `UITableViewCell` \u002F `UICollectionViewCell`\n\n> ✍️ Examples and explanations below use `UITableView` and `UITableViewCell`, but the exact same examples and explanations apply for `UICollectionView` and `UICollectionViewCell`.\n\n## 1. Declare your cells to conform to `Reusable` or `NibReusable`\n\n* Use the `Reusable` protocol if they don't depend on a NIB (this will use `registerClass(…)` to register the cell)\n* Use the `NibReusable` typealias (= `Reusable & NibLoadable`) if they use a `XIB` file for their content (this will use `registerNib(…)` to register the cell)\n\n```swift\nfinal class CustomCell: UITableViewCell, Reusable { \u002F* And that's it! *\u002F }\n```\n\n> ✍️ **Notes**\n> \n> * For cells embedded in a Storyboard's tableView, either one of those two protocols will work (as you won't need to register the cell manually anyway, since registration is handled by the storyboard automatically)\n> * If you create a XIB-based cell, don't forget to set its _Reuse Identifier_ field in Interface Builder to the same string as the name of the cell class itself.\n> * 💡 `NibReusable` is a typealias, so you could still use two protocols conformance `Reusable, NibLoadable` instead of `NibReusable`.\n\n\n\u003Cdetails>\n\u003Csummary>📑 Example for a Code-based custom tableView cell\u003C\u002Fsummary>\n\n```swift\nfinal class CodeBasedCustomCell: UITableViewCell, Reusable {\n  \u002F\u002F By default this cell will have a reuseIdentifier of \"CodeBasedCustomCell\"\n  \u002F\u002F unless you provide an alternative implementation of `static var reuseIdentifier`\n  \n  \u002F\u002F No need to add anything to conform to Reusable. You can just keep your normal cell code\n  @IBOutlet private weak var label: UILabel!\n  func fillWithText(text: String?) { label.text = text }\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>📑 Example for a Nib-based custom tableView cell\u003C\u002Fsummary>\n\n```swift\nfinal class NibBasedCustomCell: UITableViewCell, NibReusable {\n\u002F\u002F or\n\u002F\u002F final class NibBasedCustomCell: UITableViewCell, Reusable, NibLoadable {\n  \n  \u002F\u002F Here we provide a nib for this cell class (which, if we don't override the protocol's\n  \u002F\u002F default implementation of `static var nib: UINib`, will use a XIB of the same name as the class)\n  \n  \u002F\u002F No need to add anything to conform to Reusable. You can just keep your normal cell code\n  @IBOutlet private weak var pictureView: UIImageView!\n  func fillWithImage(image: UIImage?) { pictureView.image = image }\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>📑 Example for a Code-based custom collectionView cell\u003C\u002Fsummary>\n\n```swift\n\u002F\u002F A UICollectionViewCell which doesn't need a XIB to register\n\u002F\u002F Either because it's all-code, or because it's registered via Storyboard\nfinal class CodeBasedCollectionViewCell: UICollectionViewCell, Reusable {\n  \u002F\u002F The rest of the cell code goes here\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>📑 Example for a Nib-based custom collectionView cell\u003C\u002Fsummary>\n\n```swift\n\u002F\u002F A UICollectionViewCell using a XIB to define it's UI\n\u002F\u002F And that will need to register using that XIB\nfinal class NibBasedCollectionViewCell: UICollectionViewCell, NibReusable {\n\u002F\u002F or\n\u002F\u002F final class NibBasedCollectionViewCell: UICollectionViewCell, Reusable, NibLoadable {\n  \n  \u002F\u002F The rest of the cell code goes here\n  \n}\n```\n\u003C\u002Fdetails>\n\n## 2. Register your cells\n\nUnless you've prototyped your cell in a Storyboard, you'll have to register the cell class or Nib by code.\n\nTo do this, instead of calling `registerClass(…)` or `registerNib(…)` using a String-based `reuseIdentifier`, just call:\n\n```swift\ntableView.register(cellType: theCellClass.self)\n```\n\n\u003Cdetails>\n\u003Csummary>📑 Example of `UITableView` registration\u003C\u002Fsummary>\n\n```swift\nclass MyViewController: UIViewController {\n  @IBOutlet private weak var tableView: UITableView!\n  \n  override func viewDidLoad() {\n    super.viewDidLoad()\n    \u002F\u002F This will register using the class (via `register(AnyClass?, forCellReuseIdentifier: String)`)\n    \u002F\u002F because the CodeBasedCustomCell type conforms to Reusable, but not NibLoadable (nor the NibReusable typealias)\n    tableView.register(cellType: CodeBasedCustomCell.self)\n    \u002F\u002F This will register using NibBasedCustomCell.xib (via `register(UINib?, forCellReuseIdentifier: String)`)\n    \u002F\u002F because the NibBasedCustomCell type conforms to NibLoadable (via the NibReusable typealias)\n    tableView.register(cellType: NibBasedCustomCell.self)\n  }\n}\n```\n\u003C\u002Fdetails>\n\n## 3. Dequeue your cells\n\nTo dequeue a cell (typically in your `cellForRowAtIndexPath` implementation), simply call `dequeueReusableCell(indexPath:)`:\n\n```swift\n\u002F\u002F Either\nlet cell = tableView.dequeueReusableCell(for: indexPath) as MyCustomCell\n\u002F\u002F Or\nlet cell: MyCustomCell = tableView.dequeueReusableCell(for: indexPath)\n```\n\nAs long as **Swift can use type-inference to understand that you'll want a cell of type `MyCustomCell`** (either using `as MyCustomCell` or explicitly typing the receiving variable `cell: MyCustomCell`), it will magically infer both the cell class to use and thus its `reuseIdentifier` needed to dequeue the cell, and which exact type to return to save you a type-cast.\n\n* No need for you to manipulate `reuseIdentifiers` Strings manually anymore!\n* No need to force-cast the returned `UITableViewCell` instance down to your `MyCustomCell` class either!\n\n\u003Cdetails>\n\u003Csummary>📑 Example implementation of `cellForRowAtIndexPath` using `Reusable`\u003C\u002Fsummary>\n\n```swift\nextension MyViewController: UITableViewDataSource {\n  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {\n    if indexPath.section == 0 {\n      let cell = tableView.dequeueReusableCell(indexPath: indexPath) as CodeBasedCustomCell\n      \u002F\u002F Customize the cell here. You can call any type-specific methods here without the need for type-casting\n      cell.fillWithText(\"Foo\")\n      return cell\n    } else {\n      let cell = tableView.dequeueReusableCell(indexPath: indexPath) as NibBasedCustomCell\n      \u002F\u002F Customize the cell here. no need to downcasting here either!\n      cell.fillWithImage(UIImage(named:\"Bar\"))\n      return cell\n    }\n  }\n}\n```\n\u003C\u002Fdetails>\n\nNow all you have is **a beautiful code and type-safe cells**, with compile-type checking, and no more String-based API!\n\n> 💡 If the cell class you want to dequeue is computed at runtime and stored in a variable, you won't be able to use `as theVariable` or `let cell: theVariable` obviously. Instead, you can use the optional parameter `cellType` (which otherwise gets infered by the return type and is thus not necessary to provide explicitly)\n> \n> \u003Cdetails>\n> \u003Csummary>📑 Example with a cell type determined at runtime\u003C\u002Fsummary>\n> \n> ```swift\n> class ParentCell: UITableViewCell, Reusable {}\n> class Child1Cell: ParentCell {}\n> class Child2Cell: ParentCell {}\n> \n> func cellType(for indexPath: NSIndexPath) -> ParentCell.Type {\n>   return indexPath.row.isMultiple(of: 2) ? Child1Cell.self : Child2Cell.self\n> }\n> \n> func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {\n>   let cellClass = self.cellType(for: indexPath)\n>   \u002F\u002F As `self.cellType(for:)` always returns a `ParentCell` (sub-)class, the type\n>   \u002F\u002F of the variable `cell` below is infered to be `ParentCell` too. So only methods\n>   \u002F\u002F declared in the parent `ParentCell` class will be accessible on the `cell` variable.\n>   \u002F\u002F But this code will still dequeue the proper type of cell (Child1Cell or Child2Cell).\n>   let cell = tableView.dequeueReusableCell(for: indexPath, cellType: cellClass)\n>   \u002F\u002F Then fill the content of your cell (using methods\u002Fproperties from `ParentCell` type)\n>   return cell  \n> }\n> ```\n> \u003C\u002Fdetails>\n\n---\n\n\n\n# Type-safe XIB-based reusable views\n\n`Reusable` also allows you to create reusable custom views designed in Interface Builder to reuse them in other XIBs or Storyboards, or by code. This allows you to treat those views like custom UI widgets that can be used in multiple places in your app.\n\n## 1. Declare your views to conform to `NibLoadable` or `NibOwnerLoadable`\n\nIn your swift source declaring your custom view class:\n\n* Use the `NibLoadable` protocol if the XIB you're using don't use its \"File's Owner\" and the reusable view you're designing is the root view of the XIB\n* Use the `NibOwnerLoadable` protocol if you used a \"File's Owner\" of the XIB being of the class of your reusable view, and the root view(s) of the XIB is to be set as a subview providing its content.\n\n```swift\n\u002F\u002F a XIB-based custom UIView, used as root of the XIB\nfinal class NibBasedRootView: UIView, NibLoadable { \u002F* and that's it! *\u002F }\n\n\u002F\u002F a XIB-based custom UIView, used as the XIB's \"File's Owner\"\nfinal class NibBasedFileOwnerView: UIView, NibOwnerLoadable { \u002F* and that's it! *\u002F }\n```\n\n> 💡 You should use the second approach if you plan to use your custom view in another XIB or Storyboard.  \n> This will allow you to just drop a UIView in a XIB\u002FStoryboard and change its class in IB's inspector to the class of your custom XIB-based view to use it. That custom view will then automagically load its own content from the associated XIB when instantiated by the storyboard containing it, without having to write additional code to load the content of the custom view manually every time.\n\n## 2. Design your view in Interface Builder\n\nFor example if you named your class `MyCustomWidget` and made it `NibOwnerLoadable`:\n\n* Set the _File's Owner_'s class to `MyCustomWidget`\n* Design the content of the view via the root view of that XIB (which is a standard `UIView` with no custom class) and its subviews\n* Connect any `@IBOutlets` and `@IBActions` between the _File's Owner_ (the `MyCustomWidget`) and its content\n\n\u003Cdetails>\n\u003Csummary>🖼📑 A view configured to be `NibOwnerLoadable`\u003C\u002Fsummary>\n\n![NibOwnerLoadable view in Interface Builder](NibOwnerLoadable.png)\n\n```swift\nfinal class MyCustomWidget: UIView, NibOwnerLoadable {\n  @IBOutlet private var rectView: UIView!\n  @IBOutlet private var textLabel: UILabel!\n\n  @IBInspectable var rectColor: UIColor? {\n    didSet {\n      self.rectView.backgroundColor = self.rectColor\n    }\n  }\n  @IBInspectable var text: String? {\n    didSet {\n      self.textLabel.text = self.text\n    }\n  }\n…\n}\n```\n\u003C\u002Fdetails>\n\nThen that widget can be integrated in a Storyboard Scene (or any other XIB) by simply dropping a `UIView` on the Storyboard, and changing its class to `MyCustomWidget` in IB's inspector.\n\n\u003Cdetails>\n\u003Csummary>🖼 Example of a `NibOwnerLoadable` custom view once integrated in another Storyboard\u003C\u002Fsummary>\n\n* In the capture below, all blue square views have a custom class of `MyCustomWidget` set in Interface Builder.\n* When selecting one of these custom views, you have direct access to all `@IBOutlet` that this `MyCustomWidget` exposes, which allows you to connect them to other views of the Storyboard if needed\n* When selecting one of these custom views, you also have access to all the `@IBInspectable` properties. For example, in the capture below, you can see the \"Rect color\" and \"Text\" inspectable properties on the right panel, that you can change right from the Storyboard integrating your custom widget.\n\n![NibOwnerLoadable integrated in a Storyboard](NibOwnerLoadable-InStoryboard.png)\n\u003C\u002Fdetails>\n\n## 3a. Auto-loading the content of a `NibOwnerLoadable` view\n\nIf you used `NibOwnerLoadable` and made your custom view the File's Owner of your XIB, you should then override `init?(coder:)` so that it loads it's associated XIB as subviews and add constraints automatically:\n\n```swift\nfinal class MyCustomWidget: UIView, NibOwnerLoadable {\n  …\n  required init?(coder aDecoder: NSCoder) {\n    super.init(coder: aDecoder)\n    self.loadNibContent()\n  }\n}\n```\n\n`self.loadNibContent()` is a method provided by the `NibOwnerLoadable` mixin. It basically loads the content from the associated `MyCustomWidget.xib`, then add all the root views in that XIB as subviews of your `MyCustomWidget`, with appropriate layout constraints to make them the same size as your `MyCustomWidget` container view.\n\nOverriding `init?(coder:)` and calling `self.loadNibContent()` thus allows you to have that content automatically loaded by the system when that `MyCustomWidget` in included in another XIB or in a Storyboard (as `init?(coder:)` is the `init` that is called by iOS to create those instances in a XIB or Storyboard)\n\n_💡 Note: it is also possible to override `init(frame:)` similarly, in order to be able to also create an instance of that view manually via code if needed._\n\n## 3b. Instantiating a `NibLoadable` view\n\nIf you used `NibLoadable` and made your custom view the root view of your XIB (not using the File's Owner at all), these are not designed to be used in other Storyboards or XIBs like `NibOwnerLoadable` is, as they won't be able to auto-load their content.\n\nInstead, you will instantiate those `NibLoadable` views by code, which is as simple as calling `loadFromNib()` on your custom class:\n\n```swift\nlet view1 = NibBasedRootView.loadFromNib() \u002F\u002F Create one instance\nlet view2 = NibBasedRootView.loadFromNib() \u002F\u002F Create another one\nlet view3 = NibBasedRootView.loadFromNib() \u002F\u002F and another one\n…\n```\n\n---\n\n\n\n# Type-safe ViewControllers from Storyboards \n\n`Reusable` also allows you to mark your `UIViewController` classes as `StoryboardBased` or `StoryboardSceneBased` to easily instantiate them from their associated Storyboard in a type-safe way.\n\n## 1. Declare your `UIViewController` to conform to `StoryboardBased` or `StoryboardSceneBased`\n\nIn your swift source declaring your custom `UIViewController` class:\n\n* Use the `StoryboardBased` protocol if the `*.storyboard` file has the same name as the ViewController's class, and its scene is the \"initial scene\" of the storyboard.\n  * This is typically ideal if you use one Storyboard per ViewController, for example.\n* Use the `StoryboardSceneBased` protocol if scene in your storyboard has the same `sceneIdentifier` as the name of the ViewController's class, but the `*.storyboard` file name doesn't necessary match the ViewController's class name.\n  * This is typically ideal for secondary scenes in bigger storyboards\n  * You'll then be required to implement the `sceneStoryboard` type property to indicate the storyboard it belongs to.\n\n\u003Cdetails>\n\u003Csummary>📑 Example of a ViewController being the initial ViewController of its Storyboard\u003C\u002Fsummary>\n\nIn this example, `CustomVC` is designed as the initial ViewController of a Storyboard named `CustomVC.storyboard`:\n\n```swift\nfinal class CustomVC: UIViewController, StoryboardBased { \u002F* and that's it! *\u002F }\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>📑 Example of a ViewController being an arbitrary scene in a differently-named Storyboard\u003C\u002Fsummary>\n\nIn this example, `SecondaryVC` is designed in a Storyboard name `CustomVC.storyboard` (so with a different name than the class itself) and is _not_ the initial ViewController, but instead has its **\"Scene Identifier\"** set to the value `\"SecondaryVC\"` (same as the class name)\n\nConforming to `StoryboardSceneBased` will still require you to implement `static var sceneStoryboard: UIStoryboard { get }` to indicate the Storyboard where this scene is designed. You can typically implement that property using a `let` type constant:\n\n```swift\nfinal class SecondaryVC: UIViewController, StoryboardSceneBased {\n  static let sceneStoryboard = UIStoryboard(name: \"CustomVC\", bundle: nil)\n  \u002F* and that's it! *\u002F\n}\n```\n\u003C\u002Fdetails>\n\n## 2. Instantiate your UIViewControllers\n\nSimply call `instantiate()` on your custom class. This will automatically know which storyboard to load it from, and which scene (initial or not) to use to instantiate it.\n\n```swift\nfunc presentSecondary() {\n  let vc = SecondaryVC.instantiate() \u002F\u002F Init from the \"SecondaryVC\" scene of CustomVC.storyboard\n  self.present(vc, animated: true) {}\n}\n```\n\n\n\n---\n\n\n\n# Additional tips\n\n## Make your subclasses `final`\n\nI advise you to mark your custom `UITableViewCell`, `UICollectionViewCell`, `UIView` and `UIViewController` subclasses as being `final`. This is because:\n\n* In most cases, the custom cells and VCs you plan to instantiate are not intended to be subclassed themselves.\n* More importantly, it helps the compiler a lot and gives you big optimizations\n* It can be required in some cases when conforming to `protocols` that have `Self` requirements, like the ones used by this pod (`Reusable`, `StoryboardBased`, …). \n\nIn some cases you can avoid making your classes `final`, but in general it's a good practice, and in the case of this pod, usually your custom `UIViewController` or whatever won't be subclassed anyway:\n\n* Either they are intended to be used and instantiated directly and never be subclassed, so `final` makes sense here\n* In case your custom `UIViewController`, `UITableViewCell`, etc… is intended to be subclassed and be the parent class of many classes in your app, it makes more sense to **add the protocol conformance (`StoryboardBased`, `Reusable`, …) to the child classes (and mark _them_ `final`)** than adding the protocol on the parent, abstract class.\n\n## Customize reuseIdentifier, nib, etc for non-conventional uses\n\nThe protocols in this pod, like `Reusable`, `NibLoadable`, `NibOwnerLoadable`, `StoryboardBased`, `NibReusable`… are what is usually called [Mixins](http:\u002F\u002Falisoftware.github.io\u002Fswift\u002Fprotocol\u002F2015\u002F11\u002F08\u002Fmixins-over-inheritance\u002F), which basically is a Swift protocol with a default implementation provided for all of its methods.\n\nThe main benefit is that **you don't need to add any code**: just conform to `Reusable`, `NibOwnerLoadable` or any of those protocol and you're ready to go with no additional code to write.\n\nBut of course, those provided implementations are just **default implementations**. That means that if you need **you can still provide your own implementations** in case for some reason some of your cells don't follow the classic configuration of using the same name for both the class, the `reuseIdentifier` and the XIB file.\n\n```swift\nfinal class VeryCustomNibBasedCell: UITableViewCell, NibReusable {\n  \u002F\u002F This cell use a non-standard configuration: its reuseIdentifier and XIB file\n  \u002F\u002F have a different name as the class itself. So we need to provide a custom implementation or `NibReusable`\n  static var reuseIdentifier: String { return \"VeryCustomReuseIdentifier\" }\n  static var nib: UINib { return UINib(nibName: \"VeryCustomUI\", bundle: nil) } \u002F\u002F Use VeryCustomUI.xib\n  \n  \u002F\u002F Then continue with the rest of your normal cell code \n}\n```\n\nThe same is true for all the protocols of this pod, which always provide default implementations which could still be replaced by your own if you need some custom cases.\n\n_But the beauty is in 90% of cases the default implementation will match typical conventions and the default implementations will be exactly what you want!_\n\n## Type-safety and `fatalError`\n\n`Reusable` allows you to manipulate type-safe APIs and make you avoid typos. But things could still go wrong in case of a misconfguration, for example if you forgot to set the `reuseIdentifier` of your cell in its `XIB`, or you declared a `FooViewController` to be `StoryboardBased` but forgot to set the initial ViewController flag on that `FooViewController` scene in that Storyboard, etc.\n\nIn such cases, because those are developer errors that should be caught as early as possible in the development process, `Reusable` will call `fatalError` **with an error message as descriptive as possible** (instead of crashing with an obscure message about some force-cast or force-unwrap or whatnot) to help you configure it right.\n\nFor example, if `Reusable` fails to dequeue a cell, it will bail with a message like:\n\n> « Failed to dequeue a cell with identifier \\\\(cellType.reuseIdentifier) matching type \\\\(cellType.self).\n> Check that the reuseIdentifier is set properly in your XIB\u002FStoryboard and that you registered the cell beforehand. »\n\nHopefully, those explicit failure messages will allow you to understand what was misconfigured and help you fix it!\n\n\n\n---\n\n\n\n# Example Project\n\nThis repository comes with an example project in the `Example\u002F` folder. Feel free to try it.\n\nIt demonstrates how `Reusable` works for:\n\n* `UITableViewCell` and `UICollectionViewCell` subclasses,\n* Cells whose UI template is either only provided by plain code, or provided by a XIB, or prototyped directly in a Storyboard.\n* `UICollectionView`'s `SupplementaryViews` (section Headers)\n* Custom `UIView` designed in a XIB (`NibOwnerLoadable`)\n\n# Talks and Articles about Reusable\n\nThe concepts behind Reusable has been presented in various articles and talks:\n\n* [Using Generics to improve TableView cells](https:\u002F\u002Falisoftware.github.io\u002Fswift\u002Fgenerics\u002F2016\u002F01\u002F06\u002Fgeneric-tableviewcells\u002F) on my blog\n* [FrenchKit'16 talk: Mixins over Inheritance](https:\u002F\u002Fyoutu.be\u002FBSn4jlunn4I) (video)\n* Same talk was also given at NSSpain'16 ([slides](https:\u002F\u002Fspeakerdeck.com\u002Falisoftware\u002Fmixins-over-inheritance)) and AppDevCon'17 ([slides](https:\u002F\u002Fspeakerdeck.com\u002Falisoftware\u002Fmixins-over-inheritance-appdevcon-17))\n* [No more String-typed instantiations on iOS Development](https:\u002F\u002Fmedium.com\u002F@zonilyjame\u002Freusable-no-more-string-typed-instantiations-on-ios-development-aa1a4f59201c)\n\n# License\n\nThis code is distributed under the MIT license. See the `LICENSE` file for more info.\n","Reusable 是一个用于简化 Swift 中视图复用的库，支持 UITableViewCells、UICollectionViewCells 以及 UIViewControllers 等以类型安全的方式进行管理，无需直接操作字符串类型的 reuseIdentifier。此外，该库还允许通过 loadFromNib() 方法从 XIB 文件加载任意 UIView。其主要技术特点包括提供了一个 mixin 来增强视图组件的复用性，并且完全兼容 Swift 3 及以上版本。适用于需要频繁使用表格视图、集合视图或者自定义视图控制器等场景的应用开发，能够显著提高代码的可维护性和安全性。","2026-06-11 03:10:13","top_language"]