Protocol for class method
In a class definition, static
is an alias for class final
,
so it marks a type method (or property) which cannot be overridden
in subclasses.
Since you want to override the method in subclasses,
all you have to do is to define the method as class
instead of static
:
extension A: MyManagedObjectCoolStuff {
class func entityName() -> String {
return "Animal"
}
}
extension B: MyManagedObjectCoolStuff {
override class func entityName() -> String {
return "Bat"
}
}
extension C: MyManagedObjectCoolStuff {
override class func entityName() -> String {
return "Cat"
}
}
Alternatively one could use the fact that for a Core Data entity,
the class name is usually defined as <ModuleName>.<EntityName>
so that the entity name is the last component of the class name.
So you could define entityName()
as an
extension method of NSManagedObject
(the superclass of all Core Data
object classes) as in How can I create instances of managed object subclasses in a NSManagedObject Swift extension?:
extension NSManagedObject {
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = split(classString) { $0 == "." }
return components.last ?? classString
}
}
and override it only where necessary:
class A: NSManagedObject { }
class B: A { }
class C: A { }
extension C {
override class func entityName() -> String {
return "Cat"
}
}
println(A.entityName()) // A
println(B.entityName()) // B
println(C.entityName()) // Cat
Can I override a class method in a protocol the class will conform to?
As @Malik said, protocols don't seem to be the correct approach here.
You should create a BaseViewController
, define your prepareForSegue
method there and all your UIViewController
classes should inherit from it.
Now you can override prepareForSegue
for the ViewController
s where you want a custom logic.
Classmethods in Generic Protocols with self-types, mypy type checking failure
I'm not on expert on Mypy but have been teaching myself to use it recently and I think this may be due to an issue in Mypy mentioned here:
https://github.com/python/mypy/issues/3645
The issue is with handling TypeVar variables in class methods rather than anything directly to do with protocols.
The following minimal example is given in the link to show the problem.
T = TypeVar('T')
class Factory(Generic[T]):
def produce(self) -> T:
...
@classmethod
def get(cls) -> T:
return cls().produce()
class HelloWorldFactory(Factory[str]):
def produce(self) -> str:
return 'Hello World'
reveal_type(HelloWorldFactory.get()) # mypy should be able to infer 'str' here
The output from reveal_type is T rather than str. The same thing is happening with your code, where Mypy is failing to infer the type should be MyInteger
rather than _P
and so doesn't see your class as implementing the protocol. Changing the return type of the class methods to 'PType'
makes the errors go away, but I'm not confident enough to know if there are any other impacts of that change.
There's been some discussion on how best to handle it, because it's not trivial to decide what the correct behaviour should be in every case, so might be no harm flagging this to them for more use case examples (see https://github.com/python/mypy/issues/5664 for example.)
How to create class methods that conform to a protocol shared between Swift and Objective-C?
In Objective-C, we were always passing around pointers, and pointers could always be nil
. Lots of Objective-C programmers made use of the fact that sending a message to nil
did nothing and returned 0
/nil
/NO
. Swift handles nil
entirely differently. Objects either exist (never nil
), or it is unknown whether or not they exist (which is where Swift optionals come into play).
Previous to Xcode 6.3, this therefore meant that any Swift code that used any Objective-C code would have to treat all object references as Swift optionals. Nothing about Objective-C's language rules prevented an object pointer from being nil
.
What this meant for using Objective-C protocols, classes, etc., from Swift is that it was a massive mess. We had to choose between to non-perfect solutions.
Given the following Objective-C protocol:
@protocol ObjCProtocol <NSObject>
@required + (id<ObjCProtocol>)classMethod;
@required - (id<ObjCProtocol>)instanceMethod;
@required - (void)methodWithArgs:(NSObject *)args;
@end
We can either accept the method definition as containing implicitly unwrapped optionals:
class MyClass: NSObject, ObjCProtocol {
func methodWithArgs(args: NSObject!) {
// do stuff with args
}
}
This makes the resulting code cleaner (we never have to unwrap within the body), however we will always be at risk of the "found nil while unwrapping optional" error.
Or alternatively, we can define the method as being a true optional:
class MyClass: NSObject, ObjCProtocol {
func methodWithArgs(args: NSObject?) {
// unwrap do stuff with args
}
}
But this leaves us with a lot of mess unwrapping code.
Xcode 6.3 fixes this problem and adds "Nullability Annotations" for Objective-C code.
The two newly introduced keywords are nullable
and nonnull
. These are used in the same place you're declaring the return type or parameter type for your Objective-C code.
- (void)methodThatTakesNullableOrOptionalTypeParameter:(nullable NSObject *)parameter;
- (void)methodThatTakesNonnullNonOptionalTypeParameter:(nonnull NSObject *)parameter;
- (nullable NSObject *)methodReturningNullableOptionalValue;
- (nonnull NSObject *)methodReturningNonNullNonOptionalValue;
In addition to these two annotation keywords, Xcode 6.3 also introduces a set of macros that makes it easy to mark large sections of Objective-C code as nonnull
(files with no annotations at all are effectively assumed as nullable
). For this, we use NS_ASSUME_NONNULL_BEGIN
at the top of the section and NS_ASSUME_NONNULL_END
at the bottom of the section we wish to mark.
So, for example, we could wrap your entire protocol within this macro pair.
NS_ASSUME_NONNULL_BEGIN
@protocol CalcPrimesProtocol <NSObject>
- (void) calcPrimesWithComputeRecord: (ComputeRecord *) aComputeRecord
withUpdateDisplayBlock: (updateDisplayBlock) theUpdateDisplayBlock
andCompletionBlock: (calcPrimesCompletionBlock) theCalcPrimesCompletionBlock;
+ (id <CalcPrimesProtocol> ) sharedInstance;
@end
NS_ASSUME_NONNULL_END
This has the same effect as marking all of the pointer parameters and return types as nonnull
(with a few exceptions, as this entry in Apple's Swift blog makes note of).
Pre-Xcode 6.3
A Swift class that conforms to an Objective-C protocol must treat any Objective-C types in that protocol as optionals.
In trying to figure this out, I created the following Objective-C protocol:
@protocol ObjCProtocol <NSObject>
@required + (id<ObjCProtocol>)classMethod;
@required - (id<ObjCProtocol>)instanceMethod;
@required - (void)methodWithArgs:(NSObject *)args;
@end
And then, created a Swift class which inherited from NSObject
and declared itself as conforming to this ObjCProtocol
.
I then proceeded to type these method names and let Swift autocomplete the methods out for me, and this is what I got (I put in the method bodies, the rest if autocomplete):
class ASwiftClass : NSObject, ObjCProtocol {
class func classMethod() -> ObjCProtocol! {
return nil
}
func instanceMethod() -> ObjCProtocol! {
return nil
}
func methodWithArgs(args: NSObject!) {
// do stuff
}
}
Now, we can use regular optionals (with the ?
) instead of these automatically unwrapped optionals if we want. The compiler is perfectly happy with either. The point is though that we must allow for the possibility of nil
, because Objective-C protocols cannot prevent nil
from being passed.
If this protocol were implemented in Swift, we'd get to choose whether the return type is optional or not and Swift would prevent us from returning nil
to a method that didn't define a non-optional return type.
How do I call +class methods in Objective C without referencing the class?
This
id <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );
Should be
Class <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );
In the first you have an instance that conforms to <Counter>
. In the second you have a class that conforms to <Counter>
. The compiler warning is correct because instances that conform to <Counter>
don't respond to countFor:
, only classes do.
Why can't I call protocol method from class method?
The way you have your function defined in your protocol means that it will be an instance function, that is, you need an instance of the class or structure in order to call that function. When you are in a class function, you don't have an instance of that class.
If you want to call amountFromText()
from a class function, then declare it to be static
. That way, it won't need an instance of the class or structure to be called:
extension Numbers {
static func amountFromText(text: String) -> Int {
return 0
}
}
Related Topics
How to Declare a Class Level Function in Swift
How to Display Image from a Url in Swiftui
How to Identify Uppercase and Lowercase Characters in a String with Swift
Save Arfacegeometry to Obj File
How to Change the Z Index or Stack Order of Uiview
Convert Date to Integer in Swift
How to Deallocate Realitykit Arview()
How to Trigger an Action When a Swiftui Toggle() Is Toggled
How to Go from Cmutablepointer<Cgfloat> to Cgfloat[] in Swift
How to Compare Just the Time of a Date in Swift
How to Say "If X == a or B or C" as Succinctly in Swift as Possible
Libsqlite3.Dylib and Libz.Dylib Missing in Xcode 7. How to Use Parse
Uiview Background Color in Swift
How to Program a Nsoutlineview
How to Remove an Element of a Given Value from an Array in Swift