In my Swift library EVCloudKitDao I do a lot with reflection. Because of that I have set my base class of my data objects to NSObject. Now after the upgrade to Xcode 6.3 I get an error on the 2 functions for getting the hash and the description of the object. The description function was a nice to have, but i do need the hash to make my objects working with a Set.
Here is the code that I have
public class EVCloudKitDataObject : NSObject, NSCoding, Printable, Hashable, Equatable {
public func hash() -> Int {
return self.hashValue
}
public func description() -> String {
return EVReflection.description(self)
}
}
The errors that I get is:
/Users/evermeer/Desktop/dev/GitHub/EVCloudKitDao/AppMessage/AppMessage/CloudKit/EVCloudKitDataObject.swift:106:17:
Method 'hash()' with Objective-C selector 'hash' conflicts with getter
for 'hash' from superclass 'NSObject' with the same Objective-C
selector
/Users/evermeer/Desktop/dev/GitHub/EVCloudKitDao/AppMessage/AppMessage/CloudKit/EVCloudKitDataObject.swift:86:17:
Method 'description()' with Objective-C selector 'description'
conflicts with getter for 'description' from superclass 'NSObject'
with the same Objective-C selector
Does anyone know how I could solve this?
You can not use override.
As the error says, in both cases there's a naming conflict between a property and a method. The most obvious way to fix is by turning your 2 methods into properties:
public override var hash: Int {
return self.hashValue
}
public override var description: String {
return EVReflection.description(self)
}
which can also be written as:
public override var hash:Int {
get {
return self.hashValue
}
}
public override var description : String {
get {
return EVReflection.description(self)
}
}
The reason why it worked in the previous version is most likely because of this:
Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.
Read more in the release notes (search for 18391046 and 18383574)
Related
I'm working with Property wrappers in a project that is divided into few Swift package modules dependent on each others. I have been using my own property wrappers in the code, but I want to switch to Combine, as it contains a lot of similar functionalities to my own property wrappers. In the process of converting I often occur the compiler issue:
Abort trap: 6 with error message: Global is external, but doesn't have external or weak linkage!.
As the first step I have decided to get rid of this error while still using my own property wrappers, because it can occur even there, but I managed to get rid of it. But in not a clean way, and I would like to get more knowledge on what is going on, so I could proceed with Combine later - with the same errors.
Ok, so to get rid of the Abort trap: 6 with my old property wrappers I needed to switch the way I used this property in some of modules. Instead of writing and reading it directly, I access it with $property.wrappedValue. Then it works, but this is very ugly in code, and kinda denies the puropse of using a property wrapper. Could someone explain me why this error occurs? In some of the modules Im able to use it directly with no problem. I have no idea what is going on, and what I can do to resolve this. I tried to convert a lot of similar properties with Combine, and I just get more of this errors, and actually I was not even able to resolve them like this.
Please tell me what is this error about, why it happens and what I can do to resolve it.
If his helps, this is how this property wrapper is defined:
#propertyWrapper
public class ObservableChangedValue<Value: Equatable>: Observable<Value> {
public var projectedValue: ObservableChangedValue { self }
public override var wrappedValue: Value {
get { super.wrappedValue }
set { super.wrappedValue = newValue }
}
override func shouldExecuteNotifications(oldValue: Value, newValue: Value) -> Bool {
oldValue != newValue
}
}
public class Observable<Value> {
public init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
internal var observations = [Observation<Value>]() { didSet { isBeingObserved = !observations.isEmpty } }
public var wrappedValue: Value {
didSet {
guard shouldExecuteNotifications(oldValue: oldValue, newValue: wrappedValue) else { return }
observations.forEach {
$0.executeNotification(oldValue: oldValue, newValue: wrappedValue)
}
}
}
public weak var delegate: ObservableDelegate?
public var isBeingObserved = false {
didSet {
guard isBeingObserved != oldValue else { return }
delegate?.isBeingObservedChanged(isBeingObserved)
}
}
internal func shouldExecuteNotifications(oldValue: Value, newValue: Value) -> Bool { true }
}
One big thing - I have noticed that the error only occurs when I access this variable from other file than where it was defined. I added getters and setters for now, but still not a nice solution. This seems to be a compiler error, but Im not sure.
Using property wrappers in extensions from different file seems to be
causing this
see what they claims in documentation
Property wrapper types
A property wrapper type is a type that can be used as a property wrapper. There are two basic requirements for a property wrapper type:
The property wrapper type must be defined with the attribute
#propertyWrapper. The attribute indicates that the type is meant to
be used as a property wrapper type, and provides a point at which
the compiler can verify any other consistency rules.
The property wrapper type must have a property named wrappedValue,
whose access level is the same as that of the type itself. This is
the property used by the compiler to access the underlying value on
the wrapper instance.
If I declare
public class A: NSObject {
public class X { }
public init?(x: X? = nil) { }
}
all is fine. When using it like let a = A(), the initializer is called as expected.
Now, I'd like to have the nested class X private, and the parameterized init as well (has to be, of course). But a simple init?() should stay publicly available as it was before. So I write
public class B: NSObject {
private class X { }
private init?(x: X?) { }
public convenience override init?() { self.init(x: nil) }
}
But this gives an error with the init?() initializer: failable initializer 'init()' cannot override a non-failable initializer with the overridden initializer being the public init() in NSObject.
How comes I can effectively declare an initializer A.init?() without the conflict but not B.init?()?
Bonus question: Why am I not allowed to override a non-failable initializer with a failable one? The opposite is legal: I can override a failable initializer with a non-failable, which requires using a forced super.init()! and thus introduces the risk of a runtime error. To me, letting the subclass have the failable initializer feels more sensible since an extension of functionality introduces more chance of failure. But maybe I am missing something here – explanation greatly appreciated.
This is how I solved the problem for me:
I can declare
public convenience init?(_: Void) { self.init(x: nil) }
and use it like
let b = B(())
or even
let b = B()
— which is logical since its signature is (kind of) different, so no overriding here. Only using a Void parameter and omitting it in the call feels a bit strange… But the end justifies the means, I suppose. :-)
After a bit of fiddling I think I understand. Let's consider a protocol requiring this initializer and a class implementing it:
protocol I {
init()
}
class A : I {
init() {}
}
This gives the error: "Initializer requirement 'init()' can only be satisfied by a required initializer in non-final class 'A'". This makes sense, as you could always declare a subclass of A that doesn't inherit that initializer:
class B : A {
// init() is not inherited
init(n: Int) {}
}
So we need to make our initializer in A required:
class A : I {
required init() {}
}
Now if we look at the NSObject interface we can see that the initializer is not required:
public class NSObject : NSObjectProtocol {
[...]
public init()
[...]
}
We can confirm this by subclassing it, adding a different initializer and trying to use the normal one:
class MyObject : NSObject {
init(n: Int) {}
}
MyObject() // Error: Missing argument for parameter 'n:' in call
Now here comes the weird thing: We can extend NSObject to conform to the I protocol, even though it doesn't require this initializer:
extension NSObject : I {} // No error (!)
I honestly think this is either a bug or a requirement for ObjC interop to work (EDIT: It's a bug and already fixed in the latest version). This error shouldn't be possible:
extension I {
static func get() -> Self { return Self() }
}
MyObject.get()
// Runtime error: use of unimplemented initializer 'init()' for class '__lldb_expr_248.MyObject'
Now to answer your actual question:
In your second code sample, the compiler is right in that you cannot override a non-failable with a failable initializer.
In the first one, you aren't actually overriding the initializer (no override keyword either), but instead declaring a new one by which the other one can't be inherited.
Now that I wrote this much I'm not even sure what the first part of my answer has to do with your question, but it's nice to find a bug anyways.
I suggest you to do this instead:
public convenience override init() { self.init(x: nil)! }
Also have a look at the Initialization section of the Swift reference.
I tend to only put the necessities (stored properties, initializers) into my class definitions and move everything else into their own extension, kind of like an extension per logical block that I would group with // MARK: as well.
For a UIView subclass for example, I would end up with an extension for layout-related stuff, one for subscribing and handling events and so forth. In these extensions, I inevitably have to override some UIKit methods, e.g. layoutSubviews. I never noticed any issues with this approach -- until today.
Take this class hierarchy for example:
public class C: NSObject {
public func method() { print("C") }
}
public class B: C {
}
extension B {
override public func method() { print("B") }
}
public class A: B {
}
extension A {
override public func method() { print("A") }
}
(A() as A).method()
(A() as B).method()
(A() as C).method()
The output is A B C. That makes little sense to me. I read about Protocol Extensions being statically dispatched, but this ain't a protocol. This is a regular class, and I expect method calls to be dynamically dispatched at runtime. Clearly the call on C should at least be dynamically dispatched and produce C?
If I remove the inheritance from NSObject and make C a root class, the compiler complains saying declarations in extensions cannot override yet, which I read about already. But how does having NSObject as a root class change things?
Moving both overrides into their class declaration produces A A A as expected, moving only B's produces A B B, moving only A's produces C B C, the last of which makes absolutely no sense to me: not even the one statically typed to A produces the A-output any more!
Adding the dynamic keyword to the definition or an override does seem to give me the desired behavior 'from that point in the class hierarchy downwards'...
Let's change our example to something a little less constructed, what actually made me post this question:
public class B: UIView {
}
extension B {
override public func layoutSubviews() { print("B") }
}
public class A: B {
}
extension A {
override public func layoutSubviews() { print("A") }
}
(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()
We now get A B A. Here I cannot make UIView's layoutSubviews dynamic by any means.
Moving both overrides into their class declaration gets us A A A again, only A's or only B's still gets us A B A. dynamic again solves my problems.
In theory I could add dynamic to all overrides I ever do but I feel like I'm doing something else wrong here.
Is it really wrong to use extensions for grouping code like I do?
Extensions cannot/should not override.
It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide.
Extensions can add new functionality to a type, but they cannot override existing functionality.
Swift Developer Guide
The compiler is allowing you to override in the extension for compatibility with Objective-C. But it's actually violating the language directive.
😊That just reminded me of Isaac Asimov's "Three Laws of Robotics" 🤖
Extensions (syntactic sugar) define independent methods that receive their own arguments. The function that is called for i.e. layoutSubviews depends on the context the compiler knows about when the code is compiled. UIView inherits from UIResponder which inherits from NSObject so the override in the extension is permitted but should not be.
So there's nothing wrong with grouping but you should override in the class not in the extension.
Directive Notes
You can only override a superclass method i.e. load() initialize()in an extension of a subclass if the method is Objective-C compatible.
Therefore we can take a look at why it is allowing you to compile using layoutSubviews.
All Swift apps execute inside the Objective-C runtime except for when using pure Swift-only frameworks which allow for a Swift-only runtime.
As we found out the Objective-C runtime generally calls two class main methods load() and initialize() automatically when initializing classes in your app’s processes.
Regarding the dynamic modifier
From the Apple Developer Library (archive.org)
You can use the dynamic modifier to require that access to members be dynamically dispatched through the Objective-C runtime.
When Swift APIs are imported by the Objective-C runtime, there are no guarantees of dynamic dispatch for properties, methods, subscripts, or initializers. The Swift compiler may still devirtualize or inline member access to optimize the performance of your code, bypassing the Objective-C runtime. 😳
So dynamic can be applied to your layoutSubviews -> UIView Class since it’s represented by Objective-C and access to that member is always used using the Objective-C runtime.
That's why the compiler allowing you to use override and dynamic.
One of the goals of Swift is static dispatching, or rather the reduction of dynamic dispatching. Obj-C however is a very dynamic language. The situation you're seeing is borne out of the link between the 2 languages and the way they work together. It shouldn't really compile.
One of the main points about extensions is that they are for extending, not for replacing / overriding. It's clear from both the name and the documentation that this is the intention. Indeed if you take out the link to Obj-C from your code (remove NSObject as the superclass) it won't compile.
So, the compiler is trying to decide what it can statically dispatch and what it has to dynamically dispatch, and it's falling through a gap because of the Obj-C link in your code. The reason dynamic 'works' is because it's forcing Obj-C linking on everything so it's all always dynamic.
So, it isn't wrong to use extensions for grouping, that's great, but it is wrong to override in extensions. Any overrides should be in the main class itself, and call out to extension points.
There is a way to achieve a clean separation of class signature and implementation (in extensions) while maintaining the ability to have overrides in subclasses. The trick is to use variables in place of the functions
If you make sure to define each subclass in a separate swift source file, you can use computed variables for the overrides while keeping the corresponding implementation cleanly organized in extensions. This will circumvent Swift's "rules" and will make your class's API/signature neatly organized in one place:
// ---------- BaseClass.swift -------------
public class BaseClass
{
public var method1:(Int) -> String { return doMethod1 }
public init() {}
}
// the extension could also be in a separate file
extension BaseClass
{
private func doMethod1(param:Int) -> String { return "BaseClass \(param)" }
}
...
// ---------- ClassA.swift ----------
public class A:BaseClass
{
override public var method1:(Int) -> String { return doMethod1 }
}
// this extension can be in a separate file but not in the same
// file as the BaseClass extension that defines its doMethod1 implementation
extension A
{
private func doMethod1(param:Int) -> String
{
return "A \(param) added to \(super.method1(param))"
}
}
...
// ---------- ClassB.swift ----------
public class B:A
{
override public var method1:(Int) -> String { return doMethod1 }
}
extension B
{
private func doMethod1(param:Int) -> String
{
return "B \(param) added to \(super.method1(param))"
}
}
Each class's extension are able to use the same method names for the implementation because they are private and not visible to each other (as long as they are in separate files).
As you can see inheritance (using the variable name) works properly using super.variablename
BaseClass().method1(123) --> "BaseClass 123"
A().method1(123) --> "A 123 added to BaseClass 123"
B().method1(123) --> "B 123 added to A 123 added to BaseClass 123"
(B() as A).method1(123) --> "B 123 added to A 123 added to BaseClass 123"
(B() as BaseClass).method1(123) --> "B 123 added to A 123 added to BaseClass 123"
This answer it not aimed at the OP, other than the fact that I felt inspired to respond by his statement, "I tend to only put the necessities (stored properties, initializers) into my class definitions and move everything else into their own extension ...". I'm primarily a C# programmer, and in C# one can use partial classes for this purpose. For example, Visual Studio places the UI-related stuff in a separate source file using a partial class, and leaves your main source file uncluttered so you don't have that distraction.
If you search for "swift partial class" you'll find various links where Swift adherents say that Swift doesn't need partial classes because you can use extensions. Interestingly, if you type "swift extension" into the Google search field, its first search suggestion is "swift extension override", and at the moment this Stack Overflow question is the first hit. I take that to mean that problems with (lack of) override capabilities are the most searched-for topic related to Swift extensions, and highlights the fact that Swift extensions can't possibly replace partial classes, at least if you use derived classes in your programming.
Anyway, to cut a long-winded introduction short, I ran into this problem in a situation where I wanted to move some boilerplate / baggage methods out of the main source files for Swift classes that my C#-to-Swift program was generating. After running into the problem of no override allowed for these methods after moving them to extensions, I ended up implementing the following simple-minded workaround. The main Swift source files still contain some tiny stub methods that call the real methods in the extension files, and these extension methods are given unique names to avoid the override problem.
public protocol PCopierSerializable {
static func getFieldTable(mCopier : MCopier) -> FieldTable
static func createObject(initTable : [Int : Any?]) -> Any
func doSerialization(mCopier : MCopier)
}
.
public class SimpleClass : PCopierSerializable {
public var aMember : Int32
public init(
aMember : Int32
) {
self.aMember = aMember
}
public class func getFieldTable(mCopier : MCopier) -> FieldTable {
return getFieldTable_SimpleClass(mCopier: mCopier)
}
public class func createObject(initTable : [Int : Any?]) -> Any {
return createObject_SimpleClass(initTable: initTable)
}
public func doSerialization(mCopier : MCopier) {
doSerialization_SimpleClass(mCopier: mCopier)
}
}
.
extension SimpleClass {
class func getFieldTable_SimpleClass(mCopier : MCopier) -> FieldTable {
var fieldTable : FieldTable = [ : ]
fieldTable[376442881] = { () in try mCopier.getInt32A() } // aMember
return fieldTable
}
class func createObject_SimpleClass(initTable : [Int : Any?]) -> Any {
return SimpleClass(
aMember: initTable[376442881] as! Int32
)
}
func doSerialization_SimpleClass(mCopier : MCopier) {
mCopier.writeBinaryObjectHeader(367620, 1)
mCopier.serializeProperty(376442881, .eInt32, { () in mCopier.putInt32(aMember) } )
}
}
.
public class DerivedClass : SimpleClass {
public var aNewMember : Int32
public init(
aNewMember : Int32,
aMember : Int32
) {
self.aNewMember = aNewMember
super.init(
aMember: aMember
)
}
public class override func getFieldTable(mCopier : MCopier) -> FieldTable {
return getFieldTable_DerivedClass(mCopier: mCopier)
}
public class override func createObject(initTable : [Int : Any?]) -> Any {
return createObject_DerivedClass(initTable: initTable)
}
public override func doSerialization(mCopier : MCopier) {
doSerialization_DerivedClass(mCopier: mCopier)
}
}
.
extension DerivedClass {
class func getFieldTable_DerivedClass(mCopier : MCopier) -> FieldTable {
var fieldTable : FieldTable = [ : ]
fieldTable[376443905] = { () in try mCopier.getInt32A() } // aNewMember
fieldTable[376442881] = { () in try mCopier.getInt32A() } // aMember
return fieldTable
}
class func createObject_DerivedClass(initTable : [Int : Any?]) -> Any {
return DerivedClass(
aNewMember: initTable[376443905] as! Int32,
aMember: initTable[376442881] as! Int32
)
}
func doSerialization_DerivedClass(mCopier : MCopier) {
mCopier.writeBinaryObjectHeader(367621, 2)
mCopier.serializeProperty(376443905, .eInt32, { () in mCopier.putInt32(aNewMember) } )
mCopier.serializeProperty(376442881, .eInt32, { () in mCopier.putInt32(aMember) } )
}
}
Like I said in my introduction, this doesn't really answer the OP's question, but I'm hoping this simple-minded workaround might be helpful to others who wish to move methods from the main source files to extension files and run into the no-override problem.
Use POP (Protocol-Oriented Programming) to override functions in extensions.
protocol AProtocol {
func aFunction()
}
extension AProtocol {
func aFunction() {
print("empty")
}
}
class AClass: AProtocol {
}
extension AClass {
func aFunction() {
print("not empty")
}
}
let cls = AClass()
cls.aFunction()
Just wanted to add that for Objective-C classes, two separate categories can end up overwriting the same method, and it this case... well... unexpected things can happen.
The Objective-C runtime doesn't make any guarantees about which extension will be used, as described by Apple here:
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. This is less likely to be an issue if you’re using categories with your own classes, but can cause problems when using categories to add methods to standard Cocoa or Cocoa Touch classes.
It's a good thing Swift prohibits this for pure Swift classes, since this kind of overly-dynamic behaviour is a potential source of hard to detect and investigate bugs.
class SomeClass {
var someProperty: Int {
throw Err("SNAFU")
}
}
For code like the above, the swift binary complains 'error is not handled because the enclosing function is not declared 'throws'.
How do I declare that 'someProperty' 'throws' in the above?
class SomeClass {
var someProperty throws: Int {
}
}
and
class SomeClass {
var someProperty: throws Int {
}
}
and
class SomeClass {
var someProperty: Int throws {
}
}
don't seem to work.
This functionality is added for read-only computed properties in Swift 5.5 as part of SE-0310 (included in Xcode 13).
Based on SE-0310, the syntax would be:
class SomeClass {
var someProperty: Int {
get throws {
throw Err("SNAFU")
}
}
}
Here is the previous answer for versions of Swift prior to 5.5:
You cannot throw from a computed property. You must use a function if you want to throw. The Declarations section of the Language Reference part at the end of The Swift Programming Language only lists throws (and rethrows) as a keyword for function and initializer declarations.
While it's not possible (yet) to throw from computed properties in Swift, I found Chris Lattner himself adresses this very same question on one of Apple Developer Forums threads:
We agree that you should be able to mark the getters and setters as "throws" in subscripts and computed properties, but haven't gotten there yet. We are likely to support this at some time, but it isn't clear if it will make it in time for Swift 2.
Let me suggest a workaround: a property can be declared as having type of Result<DesiredPropertyType, Error>. This way it can be accessed like this:
do {
try self.failableProperty.get()
} catch {
...
}
get() is a built-in method of Swift's Result.
UPDATE: this is getting addressed in Swift 5.5 with "effectful read-only properties": https://github.com/apple/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md.
I am writing method which takes a type which conforms to a protocol and instantiates an instance of this class. When I build it, the compiler crashes with a segfault. I appreciate that this points to a compiler bug 99% of the time, but I am interested to see if what I'm trying to do is logically correct or am I just throwing absolute nonsense at the compiler and I shouldn't be surprised to see it crash.
Here is my code
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
class ClassCreator {
class func createClass(classType: CreatableClass.Type) -> CreatableClass {
return classType()
}
}
ClassCreator.createClass(ExampleClass.self)
I also tried to rule out passing a Type as a method parameter as being the root of the problem and the following code also crashes the compiler:
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
let classType: CreatableClass.Type = CreatableClass.self
let instance = classType()
So - is this just a straightforward compiler bug and does what I am trying to do seem reasonable, or is there something in my implementation that is wrong?
Edit:
This can be achieved using generics as shown #Antonio below but unfortunately i believe that isn't useful for my application.
The actual non-dumbed down use-case for doing this is something like
protocol CreatableClass {}
protocol AnotherProtocol: class {}
class ClassCreator {
let dictionary: [String : CreatableClass]
func addHandlerForType(type: AnotherProtocol.Type, handler: CreatableClass.Type) {
let className: String = aMethodThatGetsClassNameAsAString(type)
dictionary[className] = handler()
}
required init() {}
}
I usually do that by defining a generic method. Try this:
class func createClass<T: CreatableClass>(classType: T.Type) -> CreatableClass {
return classType()
}
Update
A possible workaround is to pass a closure creating a class instance, rather than passing its type:
class ClassCreator {
class func createClass(instantiator: () -> CreatableClass) -> (CreatableClass, CreatableClass.Type) {
let instance = instantiator()
let classType = instance.dynamicType
return (instance, classType)
}
}
let ret = ClassCreator.createClass { ExampleClass() }
The advantage in this case is that you can store the closure in a dictionary for example, and create more instances on demand by just knowing the key (which is something in 1:1 relationship with the class name).
I used that method in a tiny dependency injection framework I developed months ago, which I realized it works only for #objc-compatible classes only though, making it not usable for my needs...