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 Optional
s 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.
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
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 isclass 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 ofEquatable
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
How to Fix Error: This Class Is Not Key Value Coding-Compliant for the Key Tableview.'
Accessing Self from Instance Properties Which Are Closures
How to Install Package in Xcode via Swift Package Manager
Hide Tab Bar in View with Push
Should Iboutlet Be Weak or Strong Var
Swift - Lazy Var VS. Let When Creating Views Programmatically (Saving Memory)
Duplicating a Particle Emitter Effect in Sprite Kit
Swift Remove Object from Realm
Button Border with Transparent Background in Swift
How to Insert an Image Inline Uilabel in iOS 8 Using Swift
Difference Between String Interpolation and String Concatenation
Scenekit Object Between Two Points
How to Position Banner Ads Over Uitabbar