Add an Extension/Method to All Objects in Swift

Add an extension/method to all objects in Swift

No. You've pretty much answered your own question--Swift objects don't have a base class, and the only real way to get around it is to inherit from NSObject.

Is there a way to add an extension to AnyObject?

Unfortunately a workaround which does exactly the same as you want doesn't exist. So I would suggest to make a protocol which has an extension to add default implementations:

protocol A: AnyObject {}

// in Swift you would rather use this
protocol A: class {}

// add default implementations
extension A {
func aMethod() {
// code
}
}

// Example
class B: A {}

// use the method
B().aMethod()

This approach does not make all classes automatically conform to this protocol (but only classes can conform to it). So you have to make them conform yourself. Since you don't use this as much this would be a reasonable solution.

Extend all Swift Objects

No. Swift objects do not actually inherit from any root base class. The compiler may insert one as an implementation detail, but the language does not have this.

The solution is a function, and usually a generic function, rather than a method. Something that applies to "every kind of object" isn't really encapsulated. There are very few actions that apply to every conceivable thing in the universe. But functions can map absolutely anything to absolutely anything else, so are a better tool here.


Just as a note, not all objects inherit from NSObject either, and it's not a language requirement. But you're correct that the vast majority do. Take a look at NSProxy for the top of a non-NSObject tree (it implements the NSObject protocol, but does not inherit from the NSObject class). That's why id is not the same thing as NSObject*.


To your question about associated objects, this is built-in:

import Foundation

class Thing { }

let thing = Thing()

var MyKey: Character = "0"

objc_setAssociatedObject(thing, &MyKey, "I'm a value!", objc_AssociationPolicy(OBJC_ASSOCIATION_COPY))

println(objc_getAssociatedObject(thing, &MyKey))

Is this what you were trying to create? Note that objc_setAssociatedObject is also a function, not a method, in ObjC.

Swift extension with class: how to make a function to return an object's real type?

You need to introduce an extra type variable to say that the extension works on Optionals where Wrapped.Element is another Optional of any type. You have to express the "any type" part with another type variable, but you cannot add this type variable in the extension's declaration (though this feature is being proposed), or the property's declaration. What you can do instead, is to make vals a function:

func vals<T>() -> [T] where Wrapped.Element == T? {
var result = [T]()
if let arr = self{
for part in arr{
if let val = part{
result.append(val)
}
}
}
return result
}

Note that this can be simplified to:

extension Optional where Wrapped: Sequence {
func vals<T>() -> [T] where Wrapped.Element == T? {
self?.compactMap { $0 } ?? []
}
}

passing an object (self) into extension

Array already has a placeholder type for its elements: Element. Your generic parameter T is exactly that placeholder type, so you can just use Element:

extension Array {
func anotherFilter(predicate: (Element) -> Bool) -> [Element] {
var filteredArray = [Element]()
for item in self where predicate(item) {
filteredArray.append(item)
}
return filteredArray
}
}

Is there a way to apply an extension to all UIKit classes?

Not to all UIKit classes in one step, but you can simplify things a little by applying it to classes that others inherit from. For example if you add an extension to UIResponder, it gets inherited by a lot of other classes, including UIView and everything that inherits from that, plus UIViewController and all of its descendant classes. Really that's pretty much everything that shows on the screen. Beyond that, you can pick off classes like UIImage and UIColor, if they make sense.

Swift extension example

Creating an extension

Add a new swift file with File > New > File... > iOS > Source > Swift File. You can call it what you want.

The general naming convention is to call it TypeName+NewFunctionality.swift.

Sample Image

Example 1 - Double

Double+Conversions.swift

import Swift // or Foundation

extension Double {

func celsiusToFahrenheit() -> Double {
return self * 9 / 5 + 32
}

func fahrenheitToCelsius() -> Double {
return (self - 32) * 5 / 9
}
}

Usage:

let boilingPointCelsius = 100.0
let boilingPointFarenheit = boilingPointCelsius.celsiusToFahrenheit()
print(boilingPointFarenheit) // 212.0

Example 2 - String

String+Shortcuts.swift

import Swift // or Foundation

extension String {

func replace(target: String, withString: String) -> String {
return self.replacingOccurrences(of: target, with: withString)
}
}

Usage:

let newString = "the old bike".replace(target: "old", withString: "new")
print(newString) // "the new bike"

Here are some more common String extensions.

Example 3 - UIColor

UIColor+CustomColor.swift

import UIKit

extension UIColor {

class var customGreen: UIColor {
let darkGreen = 0x008110
return UIColor.rgb(fromHex: darkGreen)
}

class func rgb(fromHex: Int) -> UIColor {

let red = CGFloat((fromHex & 0xFF0000) >> 16) / 0xFF
let green = CGFloat((fromHex & 0x00FF00) >> 8) / 0xFF
let blue = CGFloat(fromHex & 0x0000FF) / 0xFF
let alpha = CGFloat(1.0)

return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}
}

See here also.

Usage:

view.backgroundColor = UIColor.customGreen

Sample Image

Notes

  • Once you define an extension it can be used anywhere in your app just like the built in class functions.
  • If you are not sure of exactly what the function or property syntax should look like, you can Option+click a similar built in method. For example, when I Option+clicked UIColor.greenColor I see the declaration is class func greenColor() -> UIColor. That gives me a good clue for how to set up my custom method.
  • Apple Documentation for Extensions
  • In Objective-C extensions are known as categories.

Extension on a collection type in Swift to find all the objects after an object

A possible implementation for arbitrary collections of
Equatable elements (explanations inline). The main
challenge is to get the parameter types and constraints right.

extension CollectionType where Generator.Element: Equatable,
SubSequence.Generator.Element == Generator.Element {

func itemsAfterItem(item: Generator.Element, limit: Index.Distance?) -> [Generator.Element] {
if let idx = indexOf(item) where idx != endIndex {
// Start after the given item:
let from = idx.advancedBy(1)
// Up to min(from + limit, endIndex):
let to = limit.map { from.advancedBy($0, limit: endIndex) } ?? endIndex
// Return slice as an array:
return Array(self[from..<to])
} else {
// Item not found, or only at the last position.
return []
}
}
}

Understanding the

 let to = limit.map { from.advancedBy($0, limit: endIndex) } ?? endIndex

part is left as an exercise to the reader :)

Examples:

[1, 2, 3, 4, 5, 6].itemsAfterItem(2, limit: 2)    // [3, 4]
["x", "y", "z"].itemsAfterItem("y", limit: 4) // ["z"]
[1, 2, 3].itemsAfterItem(7, limit: 4) // []
[1.1, 2.2, 3.3].itemsAfterItem(1.1, limit: nil) // [2.2, 3.3]

Example for a non-array collection:

"abcdef".characters.itemsAfterItem("b", limit: 2) // ["c", "d"]

PHFetchResult extension that uses it's Generic ObjectType?

This is a general issue with generic types defined in ObjC and imported to Swift. Some relevant compiler bugs:

  • [SR-1576] Swift 3 can't subscript PHFetchResult
  • [SR-2708] Extending ObjC generics in Swift 3 does not compile

In short: ObjC generics are type-erasing, Swift generics are type-preserving. You need the latter for tasks like defining type-constrained extensions, but you can't because Swift doesn't know anything about the ObjectType of any particular PHFetchResult instance.

The swift-evolution proposal that brought widespread ObjC generics import to Swift 3 included a provision for letting ObjC classes provide information about their generic type parameters at runtime... but as of today, that provision has never been implemented.

AFIAK, there's not really a solution to this problem (short of working on the Swift compiler project to improve ObjC generics support), nor similar problems like making PHFetchResult conform to Sequence or Collection.

(I've tried a few angles on extending PhotoKit classes to be more Swifty myself, without much success. About the only thing I haven't tried — largely because it's such a drastic measure — is wrapping/replacing large chunks of the API. In theory, though, you could wrap PHFetchResult in a non-generic ObjC class, then wrap that in a generic Swift type, and replace all of the PhotoKit fetch methods with ones that provide appropriately specialized versions of your wrapper type.)



Related Topics



Leave a reply



Submit