Marking an open method final in subclass - ios

Consider the following example:
open class A { // This class is from the SDK and cannot be modified in anyway.
open func aFunc() {}
}
This below is my own class and I need the class to be open for others to override. But the method should NOT be available for overriding.
open class B : A { // This has to be open for others to override.
override open func aFunc() {} // I need to make this **final** somehow so the subclasses cannot override this.
}
Is it possible to mark the aFunc() method in class B final?
I tried adding final keyword, but there's a compiler error saying
Instance method cannot be declared both 'final' and 'open'
If I remove the open keyword, there's a compiler error saying
Overriding instance method must be as accessible as the declaration it
overrides

You can do this by making the method public like this:
open class A { // This class is from the SDK and cannot be modified in anyway.
open func aFunc() {}
}
open class B : A { // This has to be open for others to override.
override final public func aFunc() {}
}
open keyword is for letting subclasses from different module to override, whereas the public keyword only gives access to different module and do not allow the overriding. If you want to override this method in only your module and not in other modules you can just make it public without final.

Related

Why does subclassing UINavigationController work but extending it doesn't? [duplicate]

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.

Use generic extended swift class in Objective-c

In my project i have many swift classes that extend generic classes. And Now i'm in a need to send data from objective-c class to these swift classes. Is there any possible way to do this ?
I have tried using #objc before class as shown below
but it didn't allow me to do this.
I followed this answer stack link. But i checked when i run my app with this code it dint create the variable in the Project-swift class as shown in below image
as the variable is not created here so it gives error while calling the variable in objective-c class.
Kindly help out with better solution.
I got my solution by creating another class which contain a protocol and i indirectly call the generic extended class.
class EntityDataTable :BaseData<EntitySw> {
}
this is the generic extended class
and the another class i made to indirectly access this class in objective-c is
#objc class EntityService : NSObject {
var entityProtocol:EntityDataProtocol?
override init() {
super.init()
entityProtocol = returnDataObject()
}
func returnDataObject() -> EntityDataTable {
return EntityDataTable()
}
}
#objc protocol EntityDataProtocol{
func addFromService(source: CWEntity)
func getAll() -> [EntitySw]
}
Then i imported the Project-swift.h file in objective c class and made the object of swift class

Can't use private property in extensions in another file

I can't use private property in extension. My extension is in another file.
How can I use private property in extension?
Update
Starting with Swift 4, extensions can access the private properties of a type declared in the same file. See Access Levels.
If a property is declared private, its access is restricted to the enclosing declaration, and to extensions of that declaration that are in the same file.
If the property is declared fileprivate, it can only be used within the file it is declared (and by anything in that file).
If the property is declared internal (the default), it can only be used within the module it is declared (and by anything in that file).
If the property is declared public or open, it can be used by anything within the module as well as outside of the module by files that import the module it is declared in.
While #nhgrif is correct about how painful is that protected is missing in Swift, There is a way around.
Wrap your object with protocol, and declare only about the methods and properties that you wish to expose.
For Example
MyUtiltyClass.swift
protocol IMyUtiltyClass {
func doSomething()
}
class MyUtiltyClass : IMyUtiltyClass {
static let shared : IMyUtiltyClass = MyUtiltyClass()
/*private*/
func doSomethingPrivately() {
}
}
MyUtiltyClass+DoSomething.swift
extension MyUtiltyClass {
func doSomething() {
self.doSomethingPrivately()
print("doing something")
}
}
And then you treat the object as the interface type and not the class/struct type directly.
MyViewController.swift
class MyViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
MyUtiltyClass.shared.doSomething()
/*
//⚠️ compiler error
MyUtiltyClass.shared.doSomethingPrivately()
*/
}
}
Happy Coding 👨‍💻
It's not a good practice to write a private variable in extensions (even if we can). It will introduce unexpected bugs.
If you want to access the variable, you can use private(set) for that variable to make it read only for outside world.
Ex.
private(set) var myPrivateVariable:Int

How to create Singleton in swift with arguments

I learn the Swift Language and i need to create a manager like a Parse sdk.
For exemple when you initialize your Parse in app you write
Parse.setApplication("...", applicationId:"...")
And later you can write code like this
Parse.doSomething()
The method doSomething() use initial context.
Can you show me in my class should look like? I try some singleton exemple, but a have MyClass.sharedAttribute.doSomething() in case
What you have shown is no indication of singletons whatsoever, it sounds and looks more like a static class with static members and properties:
class MyStatic {
static var appIdA : String?
class func setApplicationId(a : String) {
appIdA = a
}
class func doSomething() {
print(appIdA)
}
}
MyStatic.setApplicationId("blabla")
MyStatic.doSomething() // prints Optional("blabla")
Of course there is the possibility that internally the class is a singleton, but Parse does not seem to be one, just looking at the functions it exposes.
The code comments even state
/*!
The `Parse` class contains static functions that handle global configuration
for the Parse framework.
*/

Why need to set public before override viewDidLoad in a public access control viewController

Why need to set public before override viewDidload in a public access control viewController
public class customViewController: UIViewController {
override public func viewDidLoad() {
super.viewDidLoad()
}
}
if I remove the public, Xcode will give an error warning!
The error message is fairly explicit:
Overriding instance method must be as accessible as the declaration it
overrides.
This means that a method must not have a lower access level than the method it overrides.
For example given this class:
public class Superclass {
internal func doSomething() {
...
}
}
You cannot then override doSomething with a method that is less accessible than interal. e.g.
public class Subclass : Superclass {
// error
private override func doSomething() {
}
}
You can however override a method and make it more accessible:
public class Subclass : Superclass {
public override func doSomething() {
// You can even call the internal method in the superclass
super.doSomething()
}
}
The reference documentation has lots of detail on this, but seems to leave this relationship to implication.
Took from here
Public access enables entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use public access when specifying the public interface to a framework.
Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.
Private access restricts the use of an entity to the enclosing declaration. Use private access to hide the implementation details of a specific piece of functionality.
File-private access restricts the use of an entity to its own defining source file.
Do you need public modifier? You can write it like this:
class customViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
No warnings
You class declaration is:
public class customViewController: UIViewController
This opens the customViewController up to public access (publicly inherited)
Writing this gives you error:
override func viewDidLoad() {
super.viewDidLoad()
}
What happened here was an unpleasant interaction between the default access level for a method and how inheritance handles access levels.
A subclass must preserve the accessibility of its superclass’s methods
wherever the subclass might be used directly. Otherwise, we would
violate the substitution principle that allows us to treat all kinds
of UIViewController as just another UIViewController.

Resources