Swift function overriding Objective-C method - objective-c

I have an Objective-C method (declared in the class named "BaseViewModel" of my old framework) that is :
-(void) updateFromManagedObject:(__kindof NSManagedObject *)entity;
I want to use it in mutiple Swift classes. Each Swift class will use a particular subclass of NSManagedObject and inherits from "BaseViewModel". When i try to override this func like this :
override func updateFromManagedObject(entity: Person?) {
<#code#>
}
OR
override func updateFromManagedObject(entity: Animal?) {
<#code#>
}
the compiler returns :
Method does not override any method from its superclass
It only works with :
override func updateFromManagedObject(entity: NSManagedObject?) {
<#code#>
}
How can I use specifics inherited types of NSManagedObject ? (Maybe with a class Generic-Type ? I try but failed too :/ )

The point of overriding is that the subclass method is called instead of the superclass method when the receiver is an instance of the subclass. Therefore, the subclass method's parameters must handle at least all the parameters the superclass method can handle. So the subclass method's parameters' types must be the same or more general than the parameters' types for the superclass method it overrides.

You cannot overload Objective-C functions based on the argument type, as Objective-C doesn't support this kind of overloading. This is why only the NSManagedObject overriding works.
If you want different behaviour based on the entity type, an alternative would be to declare a Swift-only method:
func updateFromManagedObject2(animal: Animal) {
}
func updateFromManagedObject2(person: Person) {
}

You can't override that method because types in objective-c and swift are a bit different. the types have to line up exactly, or overriding won't work.
Both statements So the subclass method's parameters' types must be the same or more general than the parameters' types for the superclass method it overrides. and You cannot overload Objective-C functions based on the argument type, as Objective-C doesn't support this kind of overloading above are correct.
Another example of overriding illustrating this:
- (UIColor*)getDataPointColor:(int)index
{
return UIColor.whiteColor;
}
override func getDataPointColor(_ index: Int32) -> UIColor {
return UIColor.redColor
}
Note that override func getDataPointColor(_ index: Int) -> UIColor { won't work. (Not sure why, 64-bit code and all...)

Related

Kotlin - Generic With Subclass Self Type

I'd like to be able to refer to 'the current class' in a type parameter of an abstract method on a superclass. When child classes implement that method, they should have to use their own exact type.
abstract class MyBaseClass {
// This func should return a list of instances of the concrete
// subclass implementing it. The below syntax doesn't work.
abstract fun createList(): List<this::class>;
}
How should I do this?

Implement an Objective-C method with light weight generics in Swift

I have to implement this method in a DataSource protocol of an Objective-C library
(nullable id<SomeClass>)someMethod;
I am trying to implement it in my class in Swift, specifically, the AppDelegate, with what I believe keeps equal the signature
extension AppDelegate: LIBDataSource {
#objc func someMethod<T: SomeClass>() -> T? {
return nil // temporary
}
}
The problem is that
As it is, I have a warning and an error. The error says Method cannot be marked #objc because it has generic parameters (the warning below is also shown)
If I remove #objc, the warning says Non-#objc method 'someMethod()' cannot satisfy optional requirement of #objc protocol LIBDataSource
Is there a way to implement a generic Obj-C method of a Obj-C protocol in Swift? Or do I have to do a separate Objective-C class to accomplish this?
The syntax
id<SomeClass>
is nothing to do with lightweight generics, it means "any Objective-C class as long as it conforms the protocol SomeClass". Your method doesn't need to be generic but it does need to return an object that conforms to the SomeClass protocol. It's signature should probably be something like
func someMethod() -> SomeClass?

Must my swift function's return type inherit from NSObject

I have some swift function in a swift object of type Helper that returns an object of class Parameter. Parameter is defined as:
class Parameter { }
And my function like this:
func getParameter() -> Parameter { }
When accessing the methods from Helper only those that don't return anything show up. However, getParameter is uncallable. My assumption is that its return type is invisible to Obj-C. Must Parameter extend NSObject in order to work?
If you want to have your Swift classes available to Objective-C, they must inherit from an Objective-C bridged class. That's why your ViewControllers are always available, and for free-standing classes, you must make their superclass NSObject. You can also specifically note in code they are bridged by marking them: #objc class Parameter: NSObject{}

How can I make my Objective-C class conform to Swift's `Equatable` protocol?

I have an Objective-C class (that happens to be a button, but that is not important), and at another part of my (mixed language) project, I have an array of these buttons and I'd like to get the index of a button using the find() method. Like so:
func doSomethingWithThisButtonIndex(index:Int)
{
let buttons = [firstButton, secondButton, thirdButton]
if index == find(buttons, firstButton)
{
// we've selected the first button
}
}
but I'm getting the
Type 'ImplicitlyUnwrappedOptional' does not conform to protocol equatable
Okay, so lets go to Objective-C and have ButtonThing implement <Equatable>. But it doesn't recognize that.
So what am I to do?
For now I'm building around it, forcing the array to be an NSArray and using indexOfObject. But this is ugly. And frustrating.
First, in Swift write a custom == operator function for your class.
Second, also in Swift, write a class extension that adds the Equatable protocol conformance.
Perhaps, for example:
func == (lhs: YourClass, rhs: YourClass) -> Bool {
// whatever logic necessary to determine whether they are equal
return lhs === rhs
}
extension YourClass: Equatable {}
And now your class conforms to Equatable, which is Swift specific. You can not do this on the Objective-C end because you can not write custom operators for Objective-C.
If your Objective C class is an NSObject, implement isEqual:
- (BOOL)isEqual:(_Nullable id)other;
This worked for me for Array.index(of: myobject) and == comparisons. NSObject is already Equatable so using a Swift extension does not work.

Swift: overriding method with selector has incompatible type

I have declared a class method in Objective-C:
+ (id) someFunction:(NSDictionary *)param;
When I subclass the class and override this method in Swift with this:
override class func someFunction(param : NSDictionary) -> AnyObject?
I get the error:
Overriding method with selector 'someFunction:' has incompatible type
'(NSDictionary) -> AnyObject?'
How do I override the method correctly?
When I try to autocomplete that class function from somewhere else in Swift, Xcode tells me that param is an [NSObject: AnyObject]!, which makes the method declaration work:
override class func someFunction(param: [NSObject: AnyObject]!) -> AnyObject? {
return "Foo"
}
This might be a compiler bug, since I'm pretty sure that's supposed to bridge properly to NSDictionary! (it seems to be bridging one way, but not the other, or something).