Skip to content

Instantly share code, notes, and snippets.

@erica
Last active November 1, 2017 10:01
Show Gist options
  • Select an option

  • Save erica/3987ec54b8f4a580ae5fc18f4e9e7ca5 to your computer and use it in GitHub Desktop.

Select an option

Save erica/3987ec54b8f4a580ae5fc18f4e9e7ca5 to your computer and use it in GitHub Desktop.

Requesting Default Values

Many Cocoa and Cocoa Touch calls are boilerplate. They use common argument values with nearly every call. Why not take advantage of Swift's default system instead? We'd like to simplify calls like this:

dismissViewControllerAnimated(flag: true, completion: nil)

to calls like this:

dismiss()

Joe Groff:

Note that framework owners really don’t have the tools to do this right now: one cannot effectively replace an Objective-C method with a method in an overlay without breaking overriding, so framework owners who wanted to add defaults for specific APIs would likely need a way to spell the default argument in Objective-C that would work through the Clang importer.

Dave A:

I don't think we can add anything to SE-0005 now that it's accepted, but the "parameter patterns" part of this gist looks like it could be a proposal on swift-evolution for the Objective-C importer. We'd need to make sure the framework owners or their representatives participate in that review, though. The rest are still radar fodder, I think.

Background

SE-0005 introduced a number of ways in which ObjC APIs will gain default values through automatic translation. Under this accepted proposal, any method that matches one of the following patterns will now provide default values:

  • Trailing closures: nullable closure parameters will default to nil.
  • NSZones: nullable zones also default to nil. (The proposal notes that they should always be nil to begin with as they are unused in Swift.)
  • Option sets: Any type name containing the word Options defaults to [], the empty option set.
  • Dictionaries: NSDictionary parameters with names including options, attributes, and info default to [:], the empty dictionary.

Daniel Steinberg and I love this defaulting behavior and approached the Swift Evolution list to see whether we could expand defaults for Cocoa and Cocoa Touch APIs even further. David Abrahams replied that we should best proceed by putting together specific requests and file them as radars for the UIKit/AppKit teams, who would then presumably provide extensions that pass the default values.

For example, dismissViewControllerAnimated(flag: true, completion: nil) could become dismissAnimated() or better yet dismiss() when default values are available for flag and completion. There's a large-ish class of these boilerplate defaults.

Here's our preliminary list of updates that we'd like to see, and we're requesting community input to help us expand that list, so when we approach our bug reports that we've already thought through and prioritized the kinds of changes we're invested in.

Requested Defaults

Here's our current list:

Parameter patterns

  • Set a default value for any case where an imported API uses an enum parameter that offers a case named .Normal, .Default, or .Plain. For example, the action style for UIAlertAction, the view style for UIAlertViewStyleDefault, the table row action style for UITableViewRowActionStyleDefault all provide .Default options. UIBarButtonItem offers a .Plain style. Other .Plain style enums include UITableViewStyle, PKPaymentButtonType, and WKTextInputMode.

  • In any case where an imported API uses more than one parameter and one of those parameters is bundle:, default that parameter to nil. For example, for UIStoryboard's storyboardWithName:bundle: and UINib's nibWithName:bundle:, the bundle: should default to nil.

Controls

  • UIControl states should always default to .Normal, e.g. button.setTitle("Hello"). (This recommendation overlaps with the parameter name section from earlier in this write-up.)
  • UIButton actions should always default to .TouchUpInside, e.g. button.addTarget(target, action: action) (although, honestly, button.add(target: target, action: action) would be preferable)
  • UISlider and UISwitch (and probably UIStepper and UISegmentedControl) actions should always default to .ValueChanged, e.g. slider.addTarget(target, action: action)

Core Graphics

  • CG construction should always default to 0.0 values (e.g. x: 0.0, y:0.0, dX: 0.0, dY: 0.0, width: 0.0, height: 0.0). This courtesy should probably extend as well to UIEdgeInsets, UIOffsetMake, and possibly CGAffineTransform (this using identity transform defaults).

UIKit

  • UIGraphicsBeginImageContextWithOptions almost universally uses scale of 0.0. (This follows the screen scale of the current device.)
  • animated: should always default to true for UIKit controller calls. We note that calling super.viewWillAppear() is foolish. You should always pass on the argument that was passed to you. A full list of UIKit animated: references including controller and non-controller APIs is here.

Colors

  • UIColor, SKColor, and NSColor's constructors should default to alpha = 1.0

Foundation

  • NSNotificationCenter the object: parameter should default to nil.

Somewhat Controversial

  • NSLayoutConstraint can default to relation (relatedBy) .Equal, multiplier 1.0, constant 0.0, secondItem (toItem) nil, second attribute (attribute) .NotAnAttribute. One can argue that defaults should be limited to multiplier and constant as readability suffers by defaulting relation, secondItem, and secondAttribute and single-item constraints represent the minority of use-cases. However, there's also an argument for enhanced readability NSLayoutConstraint(item: view, attribute: .Width, constant: 400.0) and the defaulted arguments can still be used.

To simplify record fetches: * CKModifyRecordsOperation recordIDsToDelete: could default to nil. * CKQuery could introduce a default TruePredicate.

Please suggest additional defaults to help grow this list

@watling
Copy link

watling commented Apr 18, 2016

there are quite a few calls that are ( or should be ) optional and should default to nil too.
Like presentViewController , and several FileManager ones like createDirectoryAtPath where you often have attributes = nil
dateByAddingUnit could have [] as default for options
When creating an NSError, the dict is optional, but could default to nil
same with calendar.dateByAddingUnit
NSSortDescriptor could default to ascending ( perhaps )
CKModifyRecordsOperation could default to nil for the recordsIDsToDelete at least
Maybe CKQuery could have a default TruePredicate to make getting all records simpler.

@erica
Copy link
Author

erica commented Apr 18, 2016

@watling: attributes are already defaulted to [] for SE-0005, as are any dictionary with the name options, attributes, and info. Added the other suggestions.

@kemchenj
Copy link

kemchenj commented Jun 30, 2016

Some nilable parameter in method default to "nil"

sender

performSegueWithIdentifier(_:sender:)

showViewController(_:sender:)
showDetailViewController(_:sender:)

In many time, may be 50%? I don't really have to know which instance is the sender

bundle

// UIImage
init(named:inBundle:compatibleWithTraitCollection:)

// UINib
init(nibName:bundle:)

// NSManagedObjectManager 
mergedModelFromBundles(_:)

Most of time we specify nil to search the app’s main bundle

completion

animateWithDuration(_:animations:)
animateWithDuration(_:animations:completion:)

animateWithDuration(_:delay:options:animations:completion:)
animateWithDuration(_:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)

"completion" means nilable, optional

"completionHandler" means required

Use "completion" and "completionHandler" to draw the line.

btw, delay could default to 0

Others

// NSFileManager
URLsForDirectory(_:inDomains:)

"inDomains" default to ".userDomainMask"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment