{"id":21432310,"url":"https://github.com/electricbolt/pragmaticnib","last_synced_at":"2025-08-27T04:03:57.987Z","repository":{"id":143671593,"uuid":"114522196","full_name":"electricbolt/pragmaticnib","owner":"electricbolt","description":"A pragmatic approach to constructing custom UIView's with Nib's in Swift","archived":false,"fork":false,"pushed_at":"2018-04-28T20:50:23.000Z","size":46,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-16T22:37:47.174Z","etag":null,"topics":["interface-builder","nib","protocol-extensions","swift","xcode","xib"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/electricbolt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-17T08:48:44.000Z","updated_at":"2022-02-23T08:34:07.000Z","dependencies_parsed_at":"2023-04-16T14:56:17.451Z","dependency_job_id":null,"html_url":"https://github.com/electricbolt/pragmaticnib","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/electricbolt/pragmaticnib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electricbolt%2Fpragmaticnib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electricbolt%2Fpragmaticnib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electricbolt%2Fpragmaticnib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electricbolt%2Fpragmaticnib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/electricbolt","download_url":"https://codeload.github.com/electricbolt/pragmaticnib/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electricbolt%2Fpragmaticnib/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272289029,"owners_count":24907797,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-27T02:00:09.397Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["interface-builder","nib","protocol-extensions","swift","xcode","xib"],"created_at":"2024-11-22T23:18:05.602Z","updated_at":"2025-08-27T04:03:57.973Z","avatar_url":"https://github.com/electricbolt.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"### A pragmatic approach to constructing custom UIView's with Nib's in Swift\n\n### Problems\n\n##### Problem #1: Exposing the internal implementation\n\nAssuming that `CustomView` uses a Nib file to create the visual elements of it's user interface, the most common way of instantiating a new instance of this class is as follows:\n\n\u003e Swift\n\n```swift\nlet nib = UINib(nibName: \"CustomView\", bundle: nil)\nlet v = nib.instantiate(withOwner: nil, options: nil).first as! CustomView\nv.frame = CGRect.init(x:0, y:0, width:320, height:50)\nv.backgroundColor = UIColor.green\nv.nameLabel.text = \"Happy\"\nv.valueLabel.text = \"Holidays\"\nself.view.addSubview(v)\n```\n\nThe Nib is an implementation detail of `CustomView`, and as such shouldn't be exposed to the caller. If the developer of `CustomView` were to change from using Interface Builder to create the visual elements, to constructing the visual elements programmatically inside `init` or `init(frame:)`, then the calling code would also need to change as follows:\n\n\u003e Swift\n\n```swift\nlet v = CustomView(frame: CGRect.init(x:0, y:0, width:320, height:50)\nv.backgroundColor = UIColor.green\nv.nameLabel.text = \"Happy\"\nv.valueLabel.text = \"Holidays\"\nself.view.addSubview(v)\n```\n\n##### Problem #2: Nested view hierarchy\n\nTo hide the Nib construction implementation detail from calling code, most solutions (Stack Overflow, Medium, Ray Wenderlich etc) suggest the following pattern:\n\n\u003e Swift\n\n```swift\nclass CustomView: UIView {\n  \n  var contentView: UIView!\n  \n  required init?(coder aDecoder: NSCoder) {\n    super.init(coder: aDecoder)\n    loadNib()\n  }\n\n  override init(frame: CGRect) {\n    super.init(frame: frame)\n    loadNib()\n  }\n\n  func loadNib() {\n    let nib = UINib(nibName: \"CustomView\", bundle: nil)\n    contentView = nib.instantiateWithOwner(self, options: nil)[0] as! UIView\n    contentView = self.bounds\n    contentView = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]\n    addSubview(contentView)\n  }\n}\n```\n\nThe `CustomView` Interface Builder file that was used to create the visual elements has to be of type `UIView`, rather than a Custom Class of `CustomView`. \n\n![CustomClass](./Documentation/Images/CustomClass.png)\n\nThe Nib instantied `UIView` is then added as a subview of `CustomView`, leading to a nested `UIView` hierarchy, and all the problems that it entails.\n\n### Solutions\n\n##### Objective-C to the rescue\n\nObjective-C has long been able to solve both problems by allowing the `CustomView` subclass to instantiate it's visual elements using `loadNibNamed` inside the initializer and assigning the resulting `CustomView` to `self` as follows:\n\n\u003e Objective-C\n\n```objective-c\n- (instancetype) initWithFrame: (CGRect) frame {\n    self = [[[NSBundle mainBundle] loadNibNamed: @\"CustomView\" owner: nil options: nil] objectAtIndex: 0];\n    if (self) {\n        self.frame = frame;\n    }\n    return self;\n}\n```\nThis solves both problem #1 (exposing the internal implementation) and #2 (nested view hierarchy)\n\nThe same code cannot be achieved in Swift as you cannot assign to `self` in a Class initializer. You cannot for instance do the following:\n\n\u003e Swift\n\n```swift\npublic override convenience init(frame: CGRect) {\n  self = Bundle.main.loadNibNamed(\"CustomView\", owner:nil, options:nil)![0] as! Self;\n  self.frame = frame\n}\n```\n\nThis will result in compilation errors.\n\n##### Swift Solution - Protocol Extensions\n\nThe solution for Swift is to use protocol extensions. Initializers declared in protocol extensions are the only initializers allowed to assign to `self`.\n\n\u003e Swift\n\n```swift\nfileprivate protocol _CustomView {\n}\n\nextension CustomView: _CustomView {\n}\n\nfileprivate extension _CustomView {\n\n    init(internal: Int?) {\n        self = Bundle.main.loadNibNamed(\"CustomView\", owner:nil, options:nil)![0] as! Self;\n    }\n}\n```\n\n##### Example\n\nThe `PragmaticNib` project demonstrates both Objective-C `CustomObjCView` and Swift `CustomView` versions of loading Nibs from a bundle and assigning to `self`. The `CustomView` Interface Builder file that was used to create the visual elements has a Custom Class of `CustomView`.\n\n![CustomClassCorrect](./Documentation/Images/CustomClassCorrect.png)\n\nAll code developed in Xcode 9.2 with SDK11, Swift 4 - the solution should also work with earlier versions of Xcode and Swift.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felectricbolt%2Fpragmaticnib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felectricbolt%2Fpragmaticnib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felectricbolt%2Fpragmaticnib/lists"}