Swifty closures for UIKit and Foundation

Overview

Closures logo

Language License Release

Closures is an iOS Framework that adds closure 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 & Data Sources and Target-Action, 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.

Whether 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.


Usage Overview

Convenient Closures

Some days, you just feel like dealing with UIControl's target-action using a closure instead.

button.onTap {
    // UIButton tapped code
}
mySwitch.onChange { isOn in
    // UISwitch value changed code
}

Adding a gesture recognizer can be compacted into one method.

view.addPanGesture() { pan in
    // UIPanGesutreRecognizer recognized code
}

Populating views with an array? I gotchu.

tableView.addElements(myArray, cell: MyTableViewCell.self) { element, cell, index in
    cell.textLabel!.text = "\(element)"
}
collectionView.addFlowElements(myArray, cell: MyCustomCollectionViewCell.self) { element, cell, index in
    cell.myImageViewProperty.image = element.thumbImage
}
pickerView.addStrings(myStrings) { title, component, row in
    // UIPickerView item selected code
}

Daisy Chaining

Almost all convenience methods allow for the use of daisy chaining. This allows us to have some nice syntax sugar while implementing optional delegate methods in a concise way. Using UITextField as an example, we can organize and visualize all of the UITextFieldDelegate behavior.

textField
    .didBeginEditing {
        // UITextField did begin editing code
    }.shouldClear {
        true
    }.shouldChangeCharacters { range, string in
        // some custom character change code
        return false
}

Retain Control

At no time are you locked into using these convenience methods. For instance, UITableView does not need to be populated with an array. You can just as easily provide your own UITableViewDelegate and UITableViewDataSource handlers.

tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "Cell")
tableView
    .numberOfRows { _ in
        myArray.count
    }.cellForRow { indexPath in
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel!.text = myArray[indexPath.row]
        return cell
    }.didSelectRowAt { indexPath in
        // IndexPath selected code
}

You aren't limited to which delegate/dataSource methods you wish to implement. Similarly, you can act on any UIControl events.

anyControl.on(.touchDown) { control, event in
    // UIControlEvents.touchDown event code
}

These two UIImagePickerController 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.

UIImagePickerController(source: .camera, allow: .image) { result, picker in
    myImageView.image = result.editedImage
}.present(from: self)
let pickerController = UIImagePickerController()
pickerController.sourceType = .camera
pickerController.mediaTypes = [kUTTypeImage]
pickerController.didFinishPickingMedia { [weak self] info in
    myImageView.image = info[UIImagePickerControllerEditedImage] as? UIImage
    self?.dismiss(animated: true)
}.didCancel { [weak self] in
    self?.dismiss(animated: true)
}
self.present(pickerController, animated: true)

Dive Deeper

There 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.


   Playground

To play with the Playground 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:

Playgrounds


   Class Reference Documentation

The Reference Documentation has all of the detailed usage information including all the public methods, parameters, and convenience initializers.

Class Reference Documentation


Installation

Swift Package Manager

If using Swift Package Manager, in Xcode, go to File > Swift Packages > Add Package Dependency... and enter the following URL:

https://github.com/vhesener/Closures

CocoaPods

If using CocoaPods, add the following to your Podfile:

pod 'Closures'

Carthage

If using Carthage, add the following to your Cartfile:

github "vhesener/Closures"

Manual

Download or clone the project files found in the master branch. Drag and drop all .swift files located in the 'Closures/Source' subdirectory into your Xcode project. Check the option Copy items if needed.


Background

Inspired by BlocksKit, there was a need for a more Swifty version of the same library. The goal of this library was to provide similar usefulness, but with the following constraints:

  • Use Swift's strong-typed system as much as possible in the API.
  • Not use the Objective-C runtime. There are many reasons for this, but mostly because
    • It was arbitrarily challenging.
    • It was in the spirit of Swift.
  • Create a scalable mechanism to easily add additional closure wrappers in the future.

It is our goal to become irrelevant via sherlock. In addition to not having to support this library anymore, it would actually be flattering to have been validated by the API folks at Apple.


Want more?

If you were hoping to see an API converted using closures and came up empty handed, there's a chance all can be right. Simply vote on a feature by adding a 👍 reaction.


License

Closures is provided under the MIT License.

The MIT License (MIT)
Copyright (c) 2017 Vincent Hesener
 
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Comments
  • SwiftPM, Xcode11 and iOS 13 support

    SwiftPM, Xcode11 and iOS 13 support

    Lemme know how it looks! 🖖

    I'm sure you've given it some thought, property wrappers may save a ton of this boiler plate but more importantly be potentially a lot safer! In the midst of updating the tests I noticed a mismatched case, totally easy to do accidentally with such repetitive, dense code. Also means the tests might need to be elaborated on and test actual one to one calling.

    opened by yoiang 4
  • Use of unresolved identifier 'dismissFromPresenting'

    Use of unresolved identifier 'dismissFromPresenting'

    when I clone it from cocoapod , xcode throw me this error ,when i want to use it on my project. "UIImagePickerController.swift" extension init function "didCancel: @escaping ( _ picker: UIImagePickerController) ...."

    opened by NuGelaLiees 3
  • App Store rejection for not including NSPhotoLibraryUsageDescription

    App Store rejection for not including NSPhotoLibraryUsageDescription

    I have no use of user's photo library into my app yet my app got rejected. I created a build of my app and submitted it to iTunes Connect and got the following rejection a few minutes later in an automated email: This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data. I was able to track down the cause of the rejection to this method into UIImagePickerController.swift file: public convenience init(source: UIImagePickerControllerSourceType = .photoLibrary, allow: UIImagePickerController.MediaFilter = .image, cameraOverlay: UIView? = nil, showsCameraControls: Bool = true, didCancel: @escaping ( _ picker: UIImagePickerController) -> Void = dismissFromPresenting, didPick: @escaping (_ result: UIImagePickerController.Result, _ picker: UIImagePickerController) -> Void) {... I take it that an app that makes any UIImagePickerController call (even if it’s not actually requesting access to the user’s photo library) must include an entry for NSPhotoLibraryUsageDescription in its Info.plist.

    bug 
    opened by bhulkuKs 2
  • Dependency

    Dependency "Closures" has no shared framework schemes

    When attempting to build Closures using Carthage I receive the error

    Dependency "Closures" has no shared framework schemes

    I haven't developed a framework before but it seems that that would also preclude Closures from supporting building for specific platforms (e.g., carthage update --platform iOS)

    opened by mylesbarros 2
  • Unit testing code coverage inside the closure

    Unit testing code coverage inside the closure

    Is there any way to write Unit Test that can cover the code inside the closure block?

    For example, here's a block of code I'd like to cover. How can I trigger the textField closure?

    Screen Shot 2022-12-09 at 15 21 37

    opened by EddieLukeAtmey 1
  • UIImagePickerController: Use of unresolved identifier 'dismissFromPresenting'

    UIImagePickerController: Use of unresolved identifier 'dismissFromPresenting'

    Hello Vhesener,

    I have a problem with Closers lib, my project is using Swift 3.3 and XCode 9.3.1. After installing Closers 0.4, I got issue like this

    screen shot 2018-05-28 at 3 40 19 pm

    I'm not sure but it worked after changing dismissFromPresenting to UIImagePickerController.dismissFromPresenting

    Please review it.

    Thanks, Son Thai.

    opened by sonswift 1
  • cocoapod 找不到 Closures 这个库

    cocoapod 找不到 Closures 这个库

    [!] CocoaPods could not find compatible versions for pod "Closures": In Podfile: Closures

    Specs satisfying the Closures dependency were found, but they required a higher minimum deployment target. chenshuodeMac-mini:SSJCMall chenshuo$ pod install Analyzing dependencies [!] CocoaPods could not find compatible versions for pod "Closures": In Podfile: Closures

    Specs satisfying the Closures dependency were found, but they required a higher minimum deployment target.

    opened by cs571393 0
  • If you just need some ui tap callback by closure, you can think of using this project

    If you just need some ui tap callback by closure, you can think of using this project

    It's a very tiny project, the amount of code is much less. Supporting UIControl, UIBarButtonItem, UIGestureRecognizer, UIView tap action callback by closure.

    https://github.com/mithyer/Selector-Closure

    If you have any suggestion, tell me.

    opened by mithyer 0
  • is Closures doesn't support custom-observed property in swift ?

    is Closures doesn't support custom-observed property in swift ?

    i define an observed property, and use observe(_, until: _, changeHandler: _) to get value changed callback, most of time it works fine, but in iOS 10.3.3, i receive a crash log! crash description: " *** was deallocated while key value observers were still registered with it";

    i declare property like this class Person { @objc dynamic var age: Int = 18 }

    opened by howoften 1
  • Duplicate case in TableViewDelegate.responds(to:)

    Duplicate case in TableViewDelegate.responds(to:)

    There are two identical cases in TableViewDelegate.responds(to:), both checking TableViewDelegate.tableView(_:sectionForSectionIndexTitle:at:) (L486:L489).

    opened by mkalmes 0
  • Memory leak

    Memory leak

    In Core.swift on line 130 there is self?.removeObserver(observer!) but I believe directly after this you should have: observer = nil

    You do this currently:

    self?.removeObserver(observer!)
    observer = nil
    

    for lines 136-137 and 172-173 but I think its missing in the above scenario. I notice when I use Xcode Instruments > Leaks that I see memory leaks. Adding the above removes the leaks for me.

    opened by danh-geo 0
  • MFMailComposeViewController Support

    MFMailComposeViewController Support

    It's my first PR regarding this repo, just want to share incremental work @vhesener #15 Adding support to MFMailComposeViewController, it's not done yet

    opened by Overcot 0
Releases(0.7.0)
Owner
Vinnie Hesener
Vinnie Hesener
SwiftExtensionKit - SwiftExtensionKit is to contain generic extension helpers for UIKit and Foundation

RichAppz PureSwiftExtensionKit SwiftExtensionKit is to contain generic extension

Rich Mucha 0 Jan 31, 2022
A Swift micro-framework to easily deal with weak references to self inside closures

WeakableSelf Context Closures are one of Swift must-have features, and Swift developers are aware of how tricky they can be when they capture the refe

Vincent Pradeilles 72 Sep 1, 2022
A result builder that allows to define shape building closures

ShapeBuilder A result builder implementation that allows to define shape building closures and variables. Problem In SwiftUI, you can end up in a situ

Daniel Peter 47 Dec 2, 2022
ZIP Foundation is a library to create, read and modify ZIP archive files.

ZIP Foundation is a library to create, read and modify ZIP archive files. It is written in Swift and based on Apple's libcompression for high performa

Thomas Zoechling 1.9k Dec 27, 2022
A Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and other native frameworks.

ZamzamKit ZamzamKit is a Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and othe

Zamzam Inc. 261 Dec 15, 2022
An enhancement built on top of Foundation Framework and XCTest.

Beton is a Swift library built on top of the Foundation framework, that provides an additional layer of functionality, including easy localization, performance test measurement support, and convenience functionality. For us, Beton is primarily, but not exclusively, useful for server-side Swift engineering.

21Gram Consulting 26 Dec 10, 2022
A collection of useful result builders for Swift and Foundation value types

Swift Builders A collection of useful result builders for Swift and Foundation value types. Motivation Arrays, dictionaries, and other collection-base

David Roman 3 Oct 14, 2022
The ISO 8601 period/duration types missing in Foundation

PeriodDuration This library introduces a close equivalent to Java's PeriodDuration, motivated by the lack of support for this standard in Foundation.

David Roman 19 Jun 22, 2022
Ecolande - Application realisé pendant l'Apple foundation Program.

Ecolande Application realisé pendant l'Apple foundation Program. Ecoland est l'application qui a été réalisé pendant l'Apple Foundation Program. Nous

Bilal Larose 1 Dec 31, 2021
Synatax sugar for Measurement of Foundation.

WrappedMeasurement 2022 © Weizhong Yang a.k.a zonble Syntax sugar for NSMeasurement of Foundation. NSMeasurement and NSUnit compose a great tool to le

Weizhong Yang a.k.a zonble 8 Jan 25, 2022
HumanMeasurementSwift - Synatax sugar for Measurement of Foundation

HumanMeasurement 2022 © Weizhong Yang a.k.a zonble Syntax sugar for NSMeasuremen

Weizhong Yang a.k.a zonble 8 Jan 25, 2022
Swifty regular expressions

Regex Swifty regular expressions This is a wrapper for NSRegularExpression that makes it more convenient and type-safe to use regular expressions in S

Sindre Sorhus 311 Nov 22, 2022
Customize and resize sheets in SwiftUI with SheeKit. Utilise the power of `UISheetPresentationController` and other UIKit features.

SheeKit Customize and resize sheets in SwiftUI with SheeKit. Utilise the power of UISheetPresentationController and other UIKit features. Overview She

Eugene Dudnyk 67 Dec 31, 2022
🟣 Verge is a very tunable state-management engine on iOS App (UIKit / SwiftUI) and built-in ORM.

Verge is giving the power of state-management in muukii/Brightroom v2 development! Verge.swift ?? An effective state management architecture for iOS -

VergeGroup 478 Dec 29, 2022
Pigeon is a SwiftUI and UIKit library that relies on Combine to deal with asynchronous data.

Pigeon ?? Introduction Pigeon is a SwiftUI and UIKit library that relies on Combine to deal with asynchronous data. It is heavily inspired by React Qu

Fernando Martín Ortiz 369 Dec 30, 2022
This is a app developed in Swift, using Object Oriented Programing, UIKit user interface programmatically, API Request and Kingfisher to load remote images

iOS NOW ⭐ This is a app developed in Swift, using Object Oriented Programing, UIKit user interface programmatically, API Request and Kingfisher to loa

William Tristão de Paula 1 Dec 7, 2021
FastLayout - A UIKit or AppKit package for fast UI design

FastLayout FastLayout is a UIKit or AppKit package for fast UI design. Layout Ex

null 1 Feb 19, 2022
Swift-HorizontalPickerView - Customizable horizontal picker view component written in Swift for UIKit/iOS

Horizontal Picker View Customizable horizontal picker view component written in

Afraz Siddiqui 8 Aug 1, 2022
DGPreview - Make UIKit project enable preview feature of SwiftUI

DGPreview Make UIKit project enable preview feature of SwiftUI Requirements iOS

donggyu 5 Feb 14, 2022