{"id":3047,"url":"https://github.com/vhesener/Closures","last_synced_at":"2025-08-06T16:32:02.951Z","repository":{"id":52429073,"uuid":"97360237","full_name":"vhesener/Closures","owner":"vhesener","description":"Swifty closures for UIKit and Foundation","archived":false,"fork":false,"pushed_at":"2021-04-29T15:34:36.000Z","size":4088,"stargazers_count":1744,"open_issues_count":29,"forks_count":164,"subscribers_count":27,"default_branch":"master","last_synced_at":"2024-11-28T19:06:51.194Z","etag":null,"topics":["carthage","closures","cocoapods","convenience-methods","datasource","delegation","kvo","swift","uibutton","uicollectionview","uicontrol","uigesturerecognizer","uiimagepickercontroller","uipickerview","uiscrollview","uitableview","uitextfield","uiview"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vhesener.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-16T04:38:53.000Z","updated_at":"2024-10-22T00:11:16.000Z","dependencies_parsed_at":"2022-08-20T19:20:21.463Z","dependency_job_id":null,"html_url":"https://github.com/vhesener/Closures","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhesener%2FClosures","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhesener%2FClosures/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhesener%2FClosures/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vhesener%2FClosures/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vhesener","download_url":"https://codeload.github.com/vhesener/Closures/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228923741,"owners_count":17992572,"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","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":["carthage","closures","cocoapods","convenience-methods","datasource","delegation","kvo","swift","uibutton","uicollectionview","uicontrol","uigesturerecognizer","uiimagepickercontroller","uipickerview","uiscrollview","uitableview","uitextfield","uiview"],"created_at":"2024-01-05T20:16:29.894Z","updated_at":"2024-12-09T16:31:15.601Z","avatar_url":"https://github.com/vhesener.png","language":"Swift","funding_links":[],"categories":["Utility","Libs","Project Logo","Utility [🔝](#readme)","Examples"],"sub_categories":["Web View","Utility","Other free courses"],"readme":"![Closures logo](https://raw.githubusercontent.com/vhesener/Closures/assets/assets/logo3.1.png)\n\n[![Language](https://img.shields.io/badge/Swift-5.1-blue.svg?style=plastic\u0026colorB=68B7EB)]()\n[![License](https://img.shields.io/github/license/vhesener/Closures.svg?style=plastic\u0026colorB=68B7EB)]()\n[![Release](https://img.shields.io/github/release/vhesener/Closures.svg?style=plastic\u0026colorB=68B7EB)]()\n\n`Closures` is an iOS Framework that adds [closure](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html) handlers to many of the popular UIKit and Foundation classes. Although this framework is a substitute for some Cocoa Touch design patterns, such as [Delegation \u0026 Data Sources](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html) and [Target-Action](https://developer.apple.com/library/content/documentation/General/Conceptual/Devpedia-CocoaApp/TargetAction.html), the authors make no claim regarding which is a *better* way to accomplish the same type of task. Most of the time it is a matter of style, preference, or convenience that will determine if any of these closure extensions are beneficial.\n\nWhether you're a functional purist, dislike a particular API, or simply just want to organize your code a little bit, you might enjoy using this library.\n\n\n***\n## [Usage Overview](#usage-overview)\n\n### **Convenient Closures**\n\nSome days, you just feel like dealing with [UIControl](https://vhesener.github.io/Closures/Controls.html)'s target-action using a closure instead.\n\n```swift\nbutton.onTap {\n    // UIButton tapped code\n}\n```\n\n```swift\nmySwitch.onChange { isOn in\n    // UISwitch value changed code\n}\n```\n\n***\n\nAdding a [gesture recognizer](https://vhesener.github.io/Closures/Gesture%20Recognizers.html) can be compacted into one method.\n\n```swift\nview.addPanGesture() { pan in\n    // UIPanGesutreRecognizer recognized code\n}\n```\n\n***\n\nPopulating views with an array? I gotchu.\n\n```swift\ntableView.addElements(myArray, cell: MyTableViewCell.self) { element, cell, index in\n    cell.textLabel!.text = \"\\(element)\"\n}\n```\n\n```swift\ncollectionView.addFlowElements(myArray, cell: MyCustomCollectionViewCell.self) { element, cell, index in\n    cell.myImageViewProperty.image = element.thumbImage\n}\n```\n\n```swift\npickerView.addStrings(myStrings) { title, component, row in\n    // UIPickerView item selected code\n}\n```\n***\n### **Daisy Chaining**\n\nAlmost all convenience methods allow for the use of [daisy chaining](https://en.wikipedia.org/wiki/Method_chaining). This allows us to have some nice syntax sugar while implementing optional delegate methods in a concise way. Using [UITextField](https://vhesener.github.io/Closures/Extensions/UITextField.html) as an example, we can organize and visualize all of the `UITextFieldDelegate` behavior.\n\n```swift\ntextField\n    .didBeginEditing {\n        // UITextField did begin editing code\n    }.shouldClear {\n        true\n    }.shouldChangeCharacters { range, string in\n        // some custom character change code\n        return false\n}\n```\n***\n### **Retain Control**\n\nAt no time are you locked into using these convenience methods. For instance, [UITableView](https://vhesener.github.io/Closures/Extensions/UITableView.html) does not need to be populated with an array. You can just as easily provide your own `UITableViewDelegate` and `UITableViewDataSource` handlers.\n\n```swift\ntableView.register(MyTableViewCell.self, forCellReuseIdentifier: \"Cell\")\ntableView\n    .numberOfRows { _ in\n        myArray.count\n    }.cellForRow { indexPath in\n        let cell = tableView.dequeueReusableCell(withIdentifier: \"Cell\", for: indexPath)\n        cell.textLabel!.text = myArray[indexPath.row]\n        return cell\n    }.didSelectRowAt { indexPath in\n        // IndexPath selected code\n}\n```\n\n***\n\nYou aren't limited to which delegate/dataSource methods you wish to implement. Similarly, you can act on any\n[UIControl](https://vhesener.github.io/Closures/Extensions/UIControl.html#/s:So9UIControlC8ClosuresE2onABXDSC0A6EventsV_yAB_So7UIEventCSgtc7handlertF) events.\n\n```swift\nanyControl.on(.touchDown) { control, event in\n    // UIControlEvents.touchDown event code\n}\n```\n\n***\n\nThese two [UIImagePickerController](https://vhesener.github.io/Closures/Extensions/UIImagePickerController.html) snippets are equivalent. As you can see, there are lots of ways to provide more granular control by mixing and match various convenience methods and closure handlers.\n\t\n```swift\nUIImagePickerController(source: .camera, allow: .image) { result, picker in\n    myImageView.image = result.editedImage\n}.present(from: self)\n```\n```swift\nlet pickerController = UIImagePickerController()\npickerController.sourceType = .camera\npickerController.mediaTypes = [kUTTypeImage]\npickerController.didFinishPickingMedia { [weak self] info in\n    myImageView.image = info[UIImagePickerControllerEditedImage] as? UIImage\n    self?.dismiss(animated: true)\n}.didCancel { [weak self] in\n    self?.dismiss(animated: true)\n}\nself.present(pickerController, animated: true)\n```\n***\n## [Dive Deeper](#dive-deeper)\n\nThere are several ways to learn more about the `Closures` API, depending on your learning style. Some just like to open up Xcode and use autocomplete to view the various properties/functions. Others prefer a more documented approach. Below are some documentation options.\n\n***\n### \u003cimg src=\"https://raw.githubusercontent.com/vhesener/Closures/assets/assets/playground_Icon.png\" width=\"50\" height=\"50\"/\u003e \u0026nbsp;\u0026nbsp; **Playground**\n\nTo play with the \u003ca href=\"https://developer.apple.com/swift/blog/?id=35\"\u003ePlayground\u003c/a\u003e demo, open the `Closures` workspace (Closures.xcworkspace file), build the `Closures` framework target, then click on the `ClosuresDemo` playground, and click on the play button:\n\n![Playgrounds](https://raw.githubusercontent.com/vhesener/Closures/assets/assets/playground_general2.gif)\n\n***\n### \u003cimg src=\"https://raw.githubusercontent.com/vhesener/Closures/assets/assets/reference_Icon.png\" width=\"50\" height=\"50\"/\u003e \u0026nbsp;\u0026nbsp; **Class Reference Documentation**\n\nThe [Reference Documentation](https://vhesener.github.io/Closures) has all of the detailed usage information including all the public methods, parameters, and convenience initializers.\n\n[![Class Reference Documentation](https://raw.githubusercontent.com/vhesener/Closures/assets/assets/reference_large.png)](https://vhesener.github.io/Closures)\n\n***\n## [Installation](#installation)\n\n### **Swift Package Manager**\n\nIf using [Swift Package Manager](), in Xcode, go to `File \u003e Swift Packages \u003e Add Package Dependency...` and enter the following URL:\n\n```\nhttps://github.com/vhesener/Closures\n```\n\n### **CocoaPods**\n\nIf using [CocoaPods](https://cocoapods.org/), add the following to your Podfile:\n\n```ruby\npod 'Closures'\n```\n\n### **Carthage**\n\nIf using [Carthage](https://github.com/Carthage/Carthage), add the following to your Cartfile:\n\n```shell\ngithub \"vhesener/Closures\"\n```\n\n### **Manual**\n\nDownload or clone the project files found in the [master branch](https://github.com/vhesener/Closures). Drag and drop\nall .swift files located in the 'Closures/Source' subdirectory into your Xcode project. Check the option *Copy items\nif needed*. \n\n***\n## [Background](#background)\n\nInspired by [BlocksKit](https://github.com/BlocksKit/BlocksKit), there was a need for a more *Swifty* version\nof the same library. The goal of this library was to provide similar usefulness, but with the following\nconstraints:\n\n* Use Swift's strong-typed system as much as possible in the API.\n* Not use the [Objective-C runtime](https://github.com/BlocksKit/BlocksKit/search?utf8=%E2%9C%93\u0026q=objc_setAssociatedObject\u0026type=). \nThere are many reasons for this, but mostly because \n\t* It was arbitrarily challenging.\n\t* It was in the spirit of Swift.\n* Create a scalable mechanism to easily add additional closure wrappers in the future.\n\nIt is our goal to become irrelevant via [sherlock](http://www.urbandictionary.com/define.php?term=sherlocked).\nIn addition to not having to support this library anymore, it would actually be flattering\nto have been validated by the API folks at Apple.\n\n***\n## [Want more?](#want-more)\n\nIf you were hoping to see an API converted using closures and came up empty handed, there's a\nchance all can be right. [Simply vote on a feature](https://github.com/vhesener/Closures/labels/Closure%20API%20Request) by adding a 👍 reaction.\n\n***\n## [License](#license)\n\nClosures is provided under the [MIT License](https://github.com/vhesener/Closures/blob/master/LICENSE).\n\n```text\nThe MIT License (MIT)\nCopyright (c) 2017 Vincent Hesener\n \nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute,\nsublicense, and/or sell copies of the Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following conditions:\n \nThe above copyright notice and this permission notice shall be included in all copies or\nsubstantial portions of the Software.\n \nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\nNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvhesener%2FClosures","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvhesener%2FClosures","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvhesener%2FClosures/lists"}