I have two unrelated objects (3rd party API) that have the some of the same properties. I'd like one helper method to call that will extract the data from the properties and build a NSDate object but theObject.valueForKey does not seem to work.
I've tried this function signature func foo<T: NSObject where T: NSObjectProtocol>(record: T) -> NSDate? { ... } but no luck.
Any thoughts?
This is what protocols are for:
class ClassOne {
var dateInfo: String = ""
}
class ClassTwo {
var otherDateInfo: String = ""
}
protocol DateBuildingProtocol {
func buildDateFromDateInfo() -> NSDate
}
extension ClassOne: DateBuildingProtocol {
func buildDateFromDateInfo() -> NSDate {
// do something with self.dateInfo
return NSDate()
}
}
extension ClassTwo: DateBuildingProtocol {
func buildDateFromDateInfo() -> NSDate {
// do something with self.otherDateInfo
return NSDate()
}
}
Protocols give you the power of multiple-inheritance that some other languages have. Basically you declare a method that both classes should have, and implement the method on each class to use the specific variable you need.
If you just want to get a type that will apply to both classes and expose the common property, you can use a protocol and implement the protocol using an extension:
class Foo {
let name = "foo"
}
class Bar {
let name = "bar"
}
protocol HasName {
var name: String { get }
}
extension Foo: HasName {}
extension Bar: HasName {}
func getName(x: HasName) -> String {
return x.name
}
getName(Foo()) // "foo"
getName(Bar()) // "bar"
Related
I have a UnitDimension class given by:
class UnitDimension: {
var symbol: String
init(symbol: String) {
self.symbol = symbol
}
}
and a UnitVolume subclass of this class:
class UnitVolume: UnitDimension {
static let liter = UnitVolume(symbol: "L")
}
I want to have a protocol UnitDimensionHandler that allows me to perform some simple functions. Firstly it must have an allUnits variable:
protocol UnitDimensionHandler: class {
static var allUnits: [UnitDimension] { get }
}
Is it possible to have allUnits a generic type of array that must be a subclass of UnitDimension? I could then implement it in UnitVolume as follows:
extension UnitVolume: UnitDimensionHandler {
static var allUnits: [UnitVolume] {
return [liter]
}
}
I then want to include a function that also allows me to use a generic subclass type that initiates a UnitDimension instance:
extension UnitDimensionHandler {
static func unit(for symbol: String) -> UnitDimension? {
return allUnits.first() { $0.symbol == symbol }
}
}
such that UnitVolume.unit(for: "L") returns an optional UnitVolume rather than an optional UnitDimension.
Thanks for any help.
Yes it is possible, using associatedtype:
protocol UnitDimensionHandler: class {
// here we define `generic` type variable `Dimension`, and specify it do be descendant of `UnitDimension`
associatedtype Dimension: UnitDimension
// and use it here, instead of `UnitDimension`
static var allUnits: [Dimension] { get }
}
And
extension UnitDimensionHandler {
// same `UnitDimension` -> `Dimension` replacement
static func unit(for symbol: String) -> Dimension? {
return allUnits.first() { $0.symbol == symbol }
}
}
I have a little Problem. I need to specify a return value for a function that can return every implementation of a Protocol. For Example:
My Protocol:
protocol MyProtocol {
//some functions
}
Implementations:
class ClassA: MyProtocol {
}
class ClassB: MyProtocol {
}
The "problem" function:
func getClassByString(_ name: String) -> MyProtocol.Type {
switch name {
case "a":
return ClassA.self
case "b":
return ClassB.self
default:
return ClassC.self
}
}
//EDIT: This is where i need the result
final class Mapper<N: MyProtocol> {
public func map() -> N?{
if let klass = N.self as? MyProtocol.Type {
return klass as? N
}
return nil
}
}
Usage:
let className = "a" //this String comes from a JSON
let result = getClassByString(className)
let mappingResult = Mapper<result>().map() //undeclared identifier 'result' error
let mappingResult = Mapper<ClassA>().map() //works but i do not know if it is ClassA
The Problem is that result isn't really ClassA.Type, what it should be, it is now MyProtocol.Type and I can't pass this to the next Function.
When I give result the specific value of ClassA.self everything works. I can't cast it to as! ClassA.self because i do not know if ist has to be ClassA or ClassB or Class9000
So the question is. Is there another return type like MyProtocol.Type for the function getClassByString() or a completely different way to get ClassA.Type to result ?
I think that your problem here is not exactly as you describe - the result of your example actually does appear to be a ClassA.Type in Playground, but the problem I suspect is what you do with it next. Your protocol does not say how such types are to be instantiated in a generic fashion, so the type returned cannot be instantiated.
I've made a few changes to your example, and it now works ...
protocol MyProtocol {
//some functions
init() // To instantiate generically, there MUST be an accepted pattern for init()
}
class ClassA: MyProtocol {
required init() {}
}
class ClassB: MyProtocol {
required init() {}
}
class ClassC: MyProtocol {
required init() {}
}
func getClassByString(_ name: String) -> MyProtocol.Type {
switch name {
case "a":
return ClassA.self
case "b":
return ClassB.self
default:
return ClassC.self
}
}
let className = "a" //this String comes from a JSON
let result = getClassByString(className) // ClassA.Type
let a = result.init() // ClassA
just a quick question. I have the following code, which works just fine:
class obA: Printable {
var description: String { get { return "obA" } }
}
class obB: Printable {
var description: String { get { return "obB" } }
}
func giveObject() -> obA { return obA() }
func giveObject() -> obB { return obB() }
var a: obA = giveObject()
var b: obB = giveObject()
println(a)
println(b)
The right variant of giveObject is being called and all is well. Of course this is just a simplified case, in reality in my project there are several dozens of overloads of 'giveObject', all differing in return type. Now, I want to make a generic function to parse all these things. So, next step:
func giveGeneric<T>() -> T {
return giveObject()
}
var c: obA = giveGeneric()
println(c)
And this complains about ambiguous use of giveObject. I can understand where the error comes from, but I don't see right away how I can solve it and use a construct like this...
First of all just a note.
If the generic type of giveGeneric is simply T, then it can be anything (a String, an Int, ...). So how should giveObject() react in this case?
I mean, if you write:
let word : String = giveGeneric()
internally your generic function calls something like:
let result : String = giveObject() // Ambiguous use of giveObject
My solution
I declared a protocol as follow:
protocol MyObject {
init()
}
Then I made your 2 classes conform to the protocol
class obA: Printable, MyObject {
var description: String { get { return "obA" } }
required init() {}
}
class obB: Printable, MyObject {
var description: String { get { return "obB" } }
required init() {}
}
Finally I can write this
func giveGeneric<T:MyObject>() -> T {
return T()
}
Now I can use it:
let a1 : obA = giveGeneric()
let b1 : obB = giveGeneric()
You decide if this is the solution you were looking for or simply a workaround.
That cannot work, even if you implement a giveObject function for any possible type. Since T can be any type, the giveGeneric method cannot determine the correct overload to invoke.
The only way I can think of is by creating a huge swift with as many cases as the number of types you want to handle:
func giveGeneric<T>() -> T? {
switch "\(T.self)" {
case "\(obA.self)":
return giveObject() as obA as? T
case "\(obB.self)":
return giveObject() as obB as? T
default:
return .None
}
}
But I don't think I would use such a solution even with a gun pointed at my head - it's really ugly.
If in all your cases you create instances using a parameterless constructor, then you might create a protocol and constraint the T generic type to implement it:
protocol Instantiable {
init()
}
func giveGeneric<T: Instantiable>() -> T {
return T()
}
You can use with built-in as well as new types - for instance:
extension String : Instantiable {
// `String` already implements `init()`, so nothing to add here
}
let s: String = giveGeneric()
Alternatively, if you prefer you can make the protocol declare a static giveObject method rather than a parameterless constructor:
protocol Instantiable {
static func giveObject() -> Self
}
func giveGeneric<T: Instantiable>() -> T {
return T.giveObject()
}
extension String : Instantiable {
static func giveObject() -> String {
return String()
}
}
let s: String = giveGeneric()
I have a couple of Swift protocols that describe a general interface that I'm trying to implement in multiple ways:
protocol Identifiable
{
var identifier:String { get }
}
protocol ItemWithReference
{
var resolveReference<T:Identifiable>(callback:(T) -> ())
}
Now I want to implement the ItemWithReference protocol using CloudKit as the back end (this will eventually work with an alternate back-end as well, at which time I expect to provide an alternative implementation of the ItemWithReference protocol.
In my CloudKit implementation, I have something like this:
class CloudKitIdentifiable : Identifiable
{
...
}
class CloudKitItemWithReference : ItemWithReference
{
func resolveReference<T:Identifiable>(callback:(T) -> ())
{
// In this implementation, I want to only proceed if `T` is a CloudKitIdentifiable subtype
// But not sure how to enforce that
}
}
What I would like to do is to constrain T to be a CloudKitIdentifiable rather than just a simple Identifiable. I can't do that directly in the resolveReference declaration because then the function wouldn't conform to the ItemWithReference protocol. So instead, I am hoping to confirm that T is indeed a CloudKitIdentifiable and then invoke it's initializer to create a new instance of the class being resolved.
Is there any way in Swift to use T's metatype T.Type and determine if it is a subtype of another type? Furthermore, is there any way to invoke a required initializer that has been declared on that subtype?
try:
class CloudKitIdentifiable : Identifiable {
var identifier:String = ...
required init() {}
// you need `required`.
}
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if T.self is CloudKitIdentifiable.Type {
// do work..
let obj = (T.self as CloudKitIdentifiable.Type)()
callback(obj as T)
}
}
}
OR:
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if let CKT = T.self as? CloudKitIdentifiable.Type {
// do work..
let obj = CKT()
callback(obj as T)
}
}
}
But, In this case, you have to call resolveReference like this:
let ref = CloudKitItemWithReference()
ref.resolveReference { (obj: CloudKitIdentifiable) -> () in
// ^^^^^^^^^^^^^^^^^^^^ explicit type is necessary.
println(obj.identifier)
return
}
Rathar than that, I would recommend to use Associated Type:
protocol Identifiable {
var identifier:String { get }
}
protocol ItemWithReference {
typealias Item: Identifiable // <-- HERE is associated type
func resolveReference(callback:(Item) -> ())
}
class CloudKitIdentifiable : Identifiable {
var identifier:String
init(identifier: String) {
self.identifier = identifier
}
}
class CloudKitItemWithReference : ItemWithReference {
// `Item` associated type can be inferred from
// the parameter type of `resolveReference()`
//
// typealias Item = CloudKitIdentifiable
func resolveReference(callback:(CloudKitIdentifiable) -> ()) {
let obj = CloudKitIdentifiable(identifier: "test")
callback(obj)
}
}
let ref = CloudKitItemWithReference()
ref.resolveReference { obj in
println(obj.identifier)
return
}
Does Swift have a way of mixing in traits, a la Scala? The section of the Swift book on using extensions to add protocols to existing classes comes tantalizingly close. However, since protocols can't contain an implementation, this can't be used to mix code into a class. Is there another way?
As of Swift 2.0, yes!
Providing Default Implementations
You can use protocol extensions to provide a default implementation
to any method or property requirement of that protocol. If a
conforming type provides its own implementation of a required method
or property, that implementation will be used instead of the one
provided by the extension.
One way to simulate mixing is use generic function to provide implementation
For example with these protocols
protocol Named {
func GetName() -> String
}
protocol NamedExtension {
func GetLowercaseName() -> String
func GetUppercaseName() -> String
}
I want some class to implement GetName() and use mixing so they also get GetLowercaseName() and GetUppercaseName() without implement them
This is the implementation of NamedExtension as in free function
func GetLowercaseNameImpl<T:Named>(obj:T) -> String {
return obj.GetName().lowercaseString
}
func GetUppercaseNameImpl<T:Named>(obj:T) -> String {
return obj.GetName().uppercaseString
}
and extensions on Int
extension Int : Named {
func GetName() -> String {
return "Int"
}
}
extension Int : NamedExtension {
// use provided implementation
func GetLowercaseName() -> String {
return GetLowercaseNameImpl(self)
}
func GetUppercaseName() -> String {
return GetUppercaseNameImpl(self)
}
}
and I can use
1.GetName() // result Int
1.GetUppercaseName() // result "INT"
1.GetLowercaseName() // result "int"
I don't know Scala, but from what you're telling me it is possible to simultaneously create a protocol and an extension that extends a type to add "pseudo-trait" behavior.
For example:
protocol IsGreaterThan
{
func isGreaterThan(other:Int) -> Bool
func isNotGreaterThan(other:Int) -> Bool
}
extension Int : IsGreaterThan
{
func isGreaterThan(other:Int) -> Bool
{
return self > other
}
func isNotGreaterThan(other:Int) -> Bool
{
return !isGreaterThan(other)
}
}
The real hamstring is how generics are somewhat limited for now. I think they will improve a lot in the coming revisions of Swift.
Similar to Bryan Chen's answer:
import Foundation
protocol Named {
var name : String { get }
}
protocol NamedExtension : Named { // NB extends Named
var lowercaseName : String { get }
var uppercaseName : String { get }
}
struct NamedExtensionDefault { // Put defaults inside a struct to keep name spaces seperate
static func lowercaseName(named : NamedExtension) -> String {
return (named.name as NSString).lowercaseString
}
static func uppercaseName(named : NamedExtension) -> String {
return (named.name as NSString).uppercaseString
}
}
extension Int : NamedExtension {
var name : String {
return "Int"
}
// Use default implementation
var lowercaseName : String {
return NamedExtensionDefault.lowercaseName(self)
}
var uppercaseName : String {
return NamedExtensionDefault.uppercaseName(self)
}
}
1.name // result Int
1.uppercaseName // result "INT"
1.lowercaseName // result "int"
The main difference from Bryan's answer is that I didn't use generics because I made NamedExtension extends Named, so that the default implementations can access name.
Here's my (not yet widely tested) way of doing what I think are Scala traits in Swift 2.1.1, Playgrounds-ready, two versions:
Less flexible:
protocol BigBadProtocol {
func madFunc() -> String;
// func otherFunc();
// Maybe a couple more functions here.
}
protocol BlueMadFuncUser: BigBadProtocol {}
extension BlueMadFuncUser {
func madFunc() -> String {
return "Blue"
}
}
protocol RedMadFuncUser: BigBadProtocol {}
extension RedMadFuncUser {
func madFunc() -> String {
return "Red"
}
}
class ClearClass: BigBadProtocol {
func madFunc() -> String {
return "Clear"
}
}
class BlueClass: BlueMadFuncUser {}
class RedClass: RedMadFuncUser {}
More flexible:
protocol BigBadProtocol {
func madFunc() -> String;
// func otherFunc();
// Maybe a couple more functions here.
}
protocol BlueMadFuncUser {}
extension BigBadProtocol where Self: BlueMadFuncUser {
func madFunc() -> String {
return "Blue"
}
}
protocol RedMadFuncUser {}
extension BigBadProtocol where Self: RedMadFuncUser {
func madFunc() -> String {
return "Red"
}
}
class ClearClass: BigBadProtocol {
func madFunc() -> String {
return "Clear"
}
}
class BlueClass: BigBadProtocol, BlueMadFuncUser {}
class RedClass: BigBadProtocol, RedMadFuncUser {}
Sanity check:
var classes: [BigBadProtocol] = [ClearClass(), BlueClass(), RedClass()]
// Prints "Clear, Blue, Red\n"
print((classes.map { $0.madFunc() }).joinWithSeparator(", "))
// Print another way for Playgrounds, which appears to bug out on the lines above
var s = ""
for klass in classes {
s += klass.madFunc() + " "
}
print(s)
BlueMadFuncUser and RedMadFuncUser are two versions of a trait. My terminology might be off, but then you can independently create a second trait like that and mix and match in your classes as you please.
Would be much more challenging or boiler-plate-y to reuse logic like that with an inheritance-based approach.
I ended up wanting this pattern after finding it very useful in Hack for PHP, where from what I can tell traits are very similar to Scala's: https://docs.hhvm.com/hack/other-features/trait-and-interface-requirements)