The core libraries often show a lack of convenience methods that could make our code much tidier and compact. This also applies to outdated semantics such as UIColor.withAlphaComponent(_:)
instead of UIColor.with(alpha:)
Here are just some of the examples of conveniences, that in my opinion should be part of the frameworks rather than numerous extensions written by developers, and outdated semantics which should catch up with the language.
Conveniences
CoreGraphics
extension CGRect {
init(size: CGSize) {
self.init(origin: CGPoint.zero, size: size)
}
init(size: CGFloat) {
self.init(size: CGSize(width: size, height: size))
}
init(width: CGFloat, height: CGFloat) {
self.init(x: 0, y: 0, width: width, height: height)
}
}
extension CGSize {
init(value: CGFloat) {
self.init(width: value, height: value)
}
static func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
return CGSize.init(width: lhs.width * rhs, height: lhs.height * rhs)
}
static func *(lhs: CGFloat, rhs: CGSize) -> CGSize {
return rhs * lhs
}
static func *=(lhs: inout CGSize, rhs: CGFloat) {
lhs = lhs * rhs
}
Somewhat analogous conveniences for CGPoint with (maybe) some vector-like arithmetics.
extension CGAffineTransform {
init(scale: CGFloat) {
self.init(scaleX: scale, y: scale)
}
init(translation value: CGFloat) {
self.init(translationX: value, y: value)
}
static func translation(x: CGFloat = 0, y: CGFloat = 0) -> CGAffineTransform {
return self.init(translationX: x, y: y)
}
static func scale(x: CGFloat = 1, y: CGFloat = 1) -> CGAffineTransform {
return self.init(scaleX: x, y: y)
}
func translated(by value: CGFloat) -> CGAffineTransform {
return self.translatedBy(x: value, y: value)
}
func translated(x: CGFloat = 0, y: CGFloat = 0) -> CGAffineTransform {
return self.translatedBy(x: x, y: y)
}
func scaled(by value: CGFloat) -> CGAffineTransform {
return self.scaledBy(x: value, y: value)
}
func scaled(x: CGFloat = 1, y: CGFloat = 1) -> CGAffineTransform {
return self.scaledBy(x: x, y: y)
}
}
UIKit
extension NSLayoutAnchor {
@objc internal func constraint(_ relation: NSLayoutRelation = .equal, to anchor: NSLayoutAnchor<AnchorType>, multiplier m: CGFloat = 1.0, constant c: CGFloat = 0.0) -> NSLayoutConstraint {
... // There is no function with a multiplier in NSLayoutAnchor.
// The only way to apply one is to directly use NSLayoutConstraint, which is severely inconvenient.
}
}
extension UIViewPropertyAnimator {
// These are three initializers of UIViewPropertyAnimator
init(duration: TimeInterval, controlPoint1: CGPoint, controlPoint2: CGPoint, animations: (() -> ())?)
init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> ())?)
init(duration: TimeInterval, timing: CAMediaTimingFunction, animations: (() -> ())?)
// Now the question: Isn't this:
init(duration: TimeInterval, timing: CAMediaTimingFunction, animations: (() -> ())?)
// enough?
// (Especially if CAMediaTimingFunction is modified with some conveniences or even
// becomes an enum (see post bottom))
// Or at least get rid of the second one out of the three above?
// More like a better option rather than a convenience
}
SceneKit
SCNVector3
arithmetics.
Outdated Semantics
UIKit
extension UIColor {
func with(alpha: CGFloat) -> UIColor {
return self.withAlphaComponent(alpha)
}
}
Core Animation
Why are all these current CATransform3D
global?
extension CATransform3D: Equatable {
public var identity: CATransform3D { return CATransform3DIdentity }
public var isIdentity: Bool { return CATransform3DIsIdentity(self) }
public var inverted: CATransform3D { return CATransform3DInvert(self) }
public var affine: CGAffineTransform { return CATransform3DGetAffineTransform(self) }
public var isAffine: Bool { return CATransform3DIsAffine(self) }
static public func ==(lhs: CATransform3D, rhs: CATransform3D) -> Bool {
return CATransform3DEqualToTransform(lhs, rhs)
}
public static func from(affine: CGAffineTransform) -> CATransform3D {
return CATransform3DMakeAffineTransform(affine)
}
public static func translation(x: CGFloat, y: CGFloat, z: CGFloat) -> CATransform3D {
return CATransform3DMakeTranslation(x, y, z)
}
public static func scale(x: CGFloat, y: CGFloat, z: CGFloat) -> CATransform3D {
return CATransform3DMakeScale(x, y, z)
}
public static func rotation(_ angle: CGFloat, _ x: CGFloat, _ y: CGFloat, _ z: CGFloat) -> CATransform3D {
return CATransform3DMakeRotation(angle, x, y, z)
}
public func translated(x: CGFloat, y: CGFloat, z: CGFloat) -> CATransform3D {
return CATransform3DTranslate(self, x, y, z)
}
public func scaled(x: CGFloat, y: CGFloat, z: CGFloat) -> CATransform3D {
return CATransform3DScale(self, x, y, z)
}
public func rotated(_ angle: CGFloat, _ x: CGFloat, _ y: CGFloat, _ z: CGFloat) -> CATransform3D {
return CATransform3DRotate(self, angle, x, y, z)
}
public func concatenated(with: CATransform3D) -> CATransform3D {
return CATransform3DConcat(self, with)
}
}
extension CAMediaTimingFunction {
static var linear: CAMediaTimingFunction {
return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
}
static var easeIn: CAMediaTimingFunction {
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
}
static var easeOut: CAMediaTimingFunction {
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
}
static var easeInEaseOut: CAMediaTimingFunction {
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
}
}
Maybe CAMediaTimingFunction
at its current state should be reconsidered and become an enum?
enum CAMediaTimingFunctionm {
case linear
case easeIn
case easeOut
case easeInOut
case custom(Float, Float, Float, Float)
...
}
Concering Foundation , String
seems to revert to being a collection of characters again, so I will omit obvious subscripts that spare us from using self[self.index(startIndex, offsetBy: i)]
. That is the Standard Library, however.
P.S.
Methods with default values for all parameters can be split into several methods in case they are found confusing when called without arguments