Can you override between extensions in Swift or not? (Compiler seems confused!) - swift

I've been working on an iOS application in Swift (much of it being moved from Objective-C). I'm using Core Data and trying to use extensions to add functionality to classes auto-generated from my model. One thing I readily did in Objective-C was to add a method in a category on class A and override that method in a category on class B (which derived from A), and I was hoping to do the same in Swift.
For a while now I've had the following code in my project (and this is just one example), and though I have not used the functionality yet, the compiler has worked just fine compiling this code:
// From CellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(CellType)
class CellType: NSManagedObject {
#NSManaged var maxUses: NSNumber
#NSManaged var useCount: NSNumber
// Other properties removed for brevity
}
// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(SwitchCellType)
class SwitchCellType: CellType {
#NSManaged var targetCellXIndex: NSNumber
#NSManaged var targetCellYIndex: NSNumber
#NSManaged var targetCellType: CellType
// Other properties removed for brevity
}
// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
var typeLabel : String { get { return "Empty"; } }
func isEqualToType(otherCellType : CellType) -> Bool
{
return (self.typeLabel == otherCellType.typeLabel &&
self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
self.useCount.isEqualToNumber(otherCellType.useCount));
}
// Code removed for brevity
}
// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType // YES, this compiles with the overrides!
{
override var typeLabel : String { get { return "Switch"; } }
override func isEqualToType(otherCellType : CellType) -> Bool
{
var answer = false;
if let otherSwitchCellType = otherCellType as? SwitchCellType
{
answer = super.isEqualToType(otherCellType) &&
self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
}
return answer;
}
// Code removed for brevity
}
Hopefully some kind Swift expert out there already sees my issue, but here's how I found out about it: Recently I tried to add similar functionality using methods that have parameters and/or return values that are not built in types, but I started getting this error: Declarations in extensions cannot override yet.
To explore this issue I added the following to one of my swift files, thinking it would compile just fine:
class A
{
}
class B : A
{
}
extension A
{
var y : String { get { return "YinA"; } }
}
extension B
{
override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What??
}
To my surprise, I received the same compiler error (Declarations in extensions cannot override yet). What? But I've used that patter several times already without compiler errors.
Questions:
First, are there certain rules about overriding in extensions such that in some cases it is supposed to work but in other cases it is not? Second (and more disconcerting) why does it seem that the Swift compiler is so inconsistent? What am I missing here? Please help me restore my faith in Swift.
UPDATE:
As noted in the correct answer by Martin R, it seems you can override methods in the current version of Swift (1.1 via Xcode 6.1) as long as they (1) involve only classes derived from NSObject and (2) do not use the inout modifier. Here's some examples:
class A : NSObject { }
class B : A { }
class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }
extension A
{
var y : String { get { return "YinA"; } }
func f() -> A { return A(); }
func g(val: SubNSObject, test: Bool = false) { }
func h(val: NotSubbed, test: Bool = false) { }
func j(val: SomeEnum) { }
func k(val: SubNSObject, inout test: Bool) { }
}
extension B
{
// THESE OVERIDES DO COMPILE:
override var y : String { get { return "YinB"; } }
override func f() -> A { return A(); }
override func g(val: SubNSObject, test: Bool) { }
// THESE OVERIDES DO NOT COMPILE:
//override func h(val: NotSubbed, test: Bool = false) { }
//override func j(val: SomeEnum) { }
//override func k(val: SubNSObject, inout test: Bool) { }
}

It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject is a subclass of NSObject.
Alternatively, you can use the #objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
#objc var y : String { get { return "YinA" } }
}
extension B
{
#objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with #objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout parameters or parameters of an enum type.

I experienced this on Xcode9. Closing and reopening Xcode worked for me. Probably a bug in the compiler.

Related

Type constraints on contained generic type parameter

I expected the following code to print "extension" in both cases. But the type constraint on the extension does not take effect on the contained generic type. I see the same behavior when constraining on protocols too.
class Generic1<T1> {
func doSomething() {
print("base")
}
}
extension Generic1 where T1 == String {
func doSomething() {
print("extension")
}
}
class Generic2<T2> {
private let generic1 = Generic1<T2>()
func doSomething() {
generic1.doSomething()
}
}
Generic1<String>().doSomething() // prints extension
Generic2<String>().doSomething() // prints base
The only workaround I currently have is to constrain the outer generic as well like so:
extension Generic2 where T2 == String {
func doSomething() {
generic1.doSomething()
}
}
Why does this happen? Are there better solutions?
Edit: Just for completeness, the workaround that suited my case was the following:
class Generic1<T1> {
func doSomething() {
print("base")
}
}
class StringGeneric1: Generic1<String> {
override func doSomething() {
print("extension")
}
}
class Generic2<T2> {
private let generic1: Generic1<T2>
init (_ generic1: Generic1<T2>) {
self.generic1 = generic1
}
func doSomething() {
generic1.doSomething()
}
}
Generic1<String>().doSomething() // prints "base"
Generic2<String>(StringGeneric1()).doSomething() // prints "extension"
The problem is that methods defined in extensions are statically dispatched. So when you have:
class Generic2<T2> {
private let generic1 = Generic1<T2>()
func doSomething() {
generic1.doSomething()
}
}
The compiler cannot know here whether T2 is going to be a String or not, so it generates a call to the method in the base class. When you explicitly specify that T2 is String, then with that information, the compiler can generate a call to the extension's method here. Otherwise, though, the type of T2 isn't known until runtime, so you can't reach the extension method via static dispatch.
This may be solved when conditional conformances are added with Swift 4.2

Not able to override extensions function in another extension - Swift 4 [duplicate]

I've been working on an iOS application in Swift (much of it being moved from Objective-C). I'm using Core Data and trying to use extensions to add functionality to classes auto-generated from my model. One thing I readily did in Objective-C was to add a method in a category on class A and override that method in a category on class B (which derived from A), and I was hoping to do the same in Swift.
For a while now I've had the following code in my project (and this is just one example), and though I have not used the functionality yet, the compiler has worked just fine compiling this code:
// From CellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(CellType)
class CellType: NSManagedObject {
#NSManaged var maxUses: NSNumber
#NSManaged var useCount: NSNumber
// Other properties removed for brevity
}
// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(SwitchCellType)
class SwitchCellType: CellType {
#NSManaged var targetCellXIndex: NSNumber
#NSManaged var targetCellYIndex: NSNumber
#NSManaged var targetCellType: CellType
// Other properties removed for brevity
}
// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
var typeLabel : String { get { return "Empty"; } }
func isEqualToType(otherCellType : CellType) -> Bool
{
return (self.typeLabel == otherCellType.typeLabel &&
self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
self.useCount.isEqualToNumber(otherCellType.useCount));
}
// Code removed for brevity
}
// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType // YES, this compiles with the overrides!
{
override var typeLabel : String { get { return "Switch"; } }
override func isEqualToType(otherCellType : CellType) -> Bool
{
var answer = false;
if let otherSwitchCellType = otherCellType as? SwitchCellType
{
answer = super.isEqualToType(otherCellType) &&
self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
}
return answer;
}
// Code removed for brevity
}
Hopefully some kind Swift expert out there already sees my issue, but here's how I found out about it: Recently I tried to add similar functionality using methods that have parameters and/or return values that are not built in types, but I started getting this error: Declarations in extensions cannot override yet.
To explore this issue I added the following to one of my swift files, thinking it would compile just fine:
class A
{
}
class B : A
{
}
extension A
{
var y : String { get { return "YinA"; } }
}
extension B
{
override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What??
}
To my surprise, I received the same compiler error (Declarations in extensions cannot override yet). What? But I've used that patter several times already without compiler errors.
Questions:
First, are there certain rules about overriding in extensions such that in some cases it is supposed to work but in other cases it is not? Second (and more disconcerting) why does it seem that the Swift compiler is so inconsistent? What am I missing here? Please help me restore my faith in Swift.
UPDATE:
As noted in the correct answer by Martin R, it seems you can override methods in the current version of Swift (1.1 via Xcode 6.1) as long as they (1) involve only classes derived from NSObject and (2) do not use the inout modifier. Here's some examples:
class A : NSObject { }
class B : A { }
class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }
extension A
{
var y : String { get { return "YinA"; } }
func f() -> A { return A(); }
func g(val: SubNSObject, test: Bool = false) { }
func h(val: NotSubbed, test: Bool = false) { }
func j(val: SomeEnum) { }
func k(val: SubNSObject, inout test: Bool) { }
}
extension B
{
// THESE OVERIDES DO COMPILE:
override var y : String { get { return "YinB"; } }
override func f() -> A { return A(); }
override func g(val: SubNSObject, test: Bool) { }
// THESE OVERIDES DO NOT COMPILE:
//override func h(val: NotSubbed, test: Bool = false) { }
//override func j(val: SomeEnum) { }
//override func k(val: SubNSObject, inout test: Bool) { }
}
It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject is a subclass of NSObject.
Alternatively, you can use the #objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
#objc var y : String { get { return "YinA" } }
}
extension B
{
#objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with #objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout parameters or parameters of an enum type.
I experienced this on Xcode9. Closing and reopening Xcode worked for me. Probably a bug in the compiler.

Swift Mocking Class

As far as I know there is no possible solution for mocking and stubbing methods in swift like we were used in objc with OCMock, Mockito, etc.
I'm aware of technique described here. It is quite useful in some cases, but now I had a deadlock :)
I had a service layer where I had something like contracts(calling this method with this params will return that object as callback). This is one(greatly simplified) example:
class Bar
{
func toData() -> NSData
{
return NSData()
}
}
class Foo
{
class func fromData(data: NSData) -> Foo
{
return Foo()
}
}
class ServerManager
{
let sharedInstance = ServerManager()
class func send(request: NSData, response: (NSData)->())
{
//some networking code unrelated to the problem
response(NSData())
}
}
class MobileService1
{
final class func Contract1(request: Bar, callback: (Foo) -> ())
{
ServerManager.send(request.toData()) { responseData in
callback(Foo.fromData(responseData))
}
}
//Contract2(...), Contract3(...), etc
}
Therefore somewhere in the code I had following scenario:
func someWhereInTheCode(someBool: Bool, someObject: Bar)
{
if someBool
{
MobileService1.Contract1(someObject) { resultFoo in
//self.Foo = resultFoo
}
}
else
{
//MobileService1.Contract2(...)
}
}
And the question now is how the heck could I test this? Is there better(for testing) alternative for code structure without touching contracts themselves?
Better late than never I found a solution. Just make dependency injection of the MobileService1(or better of it's interface) and then mock it easily:
//declaring interface
protocol MobileServiceContracts: class {
static func Contract1(request: Bar, callback: (Foo) -> ())
}
//make implementation to conform to interface
class MobileService1 : MobileServiceContracts
{
final class func Contract1(request: Bar, callback: (Foo) -> ())
{
ServerManager.send(request.toData()) { responseData in
callback(Foo.fromData(responseData))
}
}
//Contract2(...), Contract3(...), etc
}
//inject service
func someWhereInTheCode(someBool: Bool, someObject: Bar, serviceProvider: MobileServiceContracts.Type = MobileService1.self)
{
if someBool
{
serviceProvider.Contract1(someObject) { resultFoo in
//self.Foo = resultFoo
}
}
else
{
//MobileService1.Contract2(...)
}
}
Now you can easily change service in your tests:
class MockedMobileService1: MobileServiceContracts
{
static func Contract1(request: Bar, callback: (Foo) -> ()) {
//do whatever with the mock
}
}
someWhereInTheCode(false, someObject: Bar(), serviceProvider: MockedMobileService1.self)
And the best part is with default values you can still call it the old way(not braking change):
someWhereInTheCode(false, someObject: Bar())
Meanwhile, you can do mocking with Cuckoo, which is similar to Mockito.
Example Classes:
class ExampleObject {
var number: Int = 0
func evaluate(number: Int) -> Bool {
return self.number == number
}
}
class ExampleChecker {
func check(object: ExampleObject) -> Bool {
return object.evaluate(5)
}
}
Example Test:
#testable import App
import Cuckoo
import XCTest
class ExampleCheckerTests: XCTestCase {
func testCheck() {
// 1. Arrange
let object = MockExampleObject().spy(on: ExampleObject())
stub(object) { object in
when(object.evaluate(any())).thenDoNothing()
}
let checker = ExampleChecker()
// 2. Action
checker.check(object)
// 3. Assert
_ = verify(object).number.get
verify(object).evaluate(any())
verifyNoMoreInteractions(object)
}
}
There’s a much better framework called Mockingbird.
It’s super simple to setup and dynamically builds your mocks as the application builds to run the tests. Here’s an article that explains how some of it works

How do I make a referential type comparison in Swift using 'is'?

I can't figure out how to make a type comparison in Swift using the is operator, if the right side is a reference and not a hard-coded type.
For example,
class GmBuilding { }
class GmOffice: GmBuilding { }
class GmFactory: GmBuilding { }
class GmStreet {
var buildings: [GmBuilding] = []
func findAllBuildingsOfType(buildingType: GmBuilding.Type) -> [GmBuilding] {
var result: [GmBuilding] = []
for building in self.buildings {
if building is buildingType { // complains that buildingType is not a type
result.append(building)
}
}
return result
}
}
let myStreet = GmStreet()
var buildingList: [GmBuilding] = myStreet.findAllBuildingsOfType(GmOffice.self)
It complains that 'buildingType is not a type'. How can it be made to work?
A generic method may do what you want:
func findAllBuildingsOfType<T: GmBuilding>(buildingType: T.Type) -> [GmBuilding] {
// you can use `filter` instead of var/for/append
return buildings.filter { $0 is T }
}
This will work so long as you really do only want to determine the type at compile time:
let myStreet = GmStreet()
let buildingList = myStreet.findAllBuildingsOfType(GmOffice.self)
// T is set at compile time to GmOffice --------^
However, often when this question comes up, the follow-up question is, how do I store GmOffice.self in a variable and then have the type be determined at runtime? And that will not work with this technique. But if statically fixed types at compile time are enough for you, this should do it.
If AirSpeed Velocity's answer doesn't work for you, you can also accomplish this by bridging to Objective-C.
Make GmBuilding inherit from NSObject:
class GmBuilding: NSObject { }
And use isKindOfClass(_:) to check the type:
for building in self.buildings {
if building.isKindOfClass(buildingType) {
result.append(building)
}
}
Not as Swifty, but it works.
I'm sure there must be a better way than this, but it doesn't require inheritance from NSObject and it works at runtime - according to my playground
class GmBuilding { }
class GmOffice: GmBuilding { }
class GmFactory: GmBuilding { }
func thingIs(thing: GmBuilding, #sameTypeAs: GmBuilding) -> Bool
{
return thing.dynamicType === sameTypeAs.dynamicType
}
var foo: GmOffice = GmOffice()
thingIs(foo, sameTypeAs: GmOffice()) // true
thingIs(foo, sameTypeAs: GmFactory()) // false
The main reason I instantiate an object (you can use a singleton instead) is because I can't figure out how to declare a parameter to be a metatype.
It also doesn't work for
thingIs(foo, sameTypeAs: GmBuilding()) // false :=(
As a final resort, using Obj-C reflect function:
import ObjectiveC
func isinstance(instance: AnyObject, cls: AnyClass) -> Bool {
var c: AnyClass? = instance.dynamicType
do {
if c === cls {
return true
}
c = class_getSuperclass(c)
} while c != nil
return false
}
class GmBuilding { }
class GmOffice: GmBuilding { }
class GmFactory: GmBuilding { }
isinstance(GmOffice(), GmOffice.self) // -> true
isinstance(GmOffice(), GmFactory.self) // -> false
isinstance(GmOffice(), GmBuilding.self) // -> true

Can I simulate traits/mixins in Swift?

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)