8

as we know, if you need to override a method in base class in swift, you have to declare "override" keyword before that method. if that method is private, you can still "override" it in swift, just add NO override keyword. However, you can not call super.MethodName(), that's my problem.

say, there's a private method in UINavigationController, namely "_startCustomTransition", I can do this in my custom MyNavigationController.swift

class MyNavigationController: UINavigationController {
    func _startCustomTransition() {
        // I can not call super._startCustomTransition()
    }
}

So, how can I do that super call? Thanks.

george
  • 83
  • 1
  • 6
  • You should be able to call performSelector: (https://stackoverflow.com/questions/41951473/perform-selector-with-object-in-swift-3) with super --- or use method swizzling (https://stackoverflow.com/questions/39562887/how-to-implement-method-swizzling-swift-3-0) to achieve this behavior. – Amresh Jul 21 '17 at 03:59
  • The reason you can't call super is because your class `MyNavigationController` is inheriting from the class `UINavigationController` and it doesn't have a method called `_startCustomTransition()` in this case using the `#selector` approach is most likely your best bet as Amresh Kumar has mentioned – CarpenterBlood Jul 21 '17 at 04:07

2 Answers2

6

You must deceive the Swift compiler that such method exists. For that you can simply add an Object-C extension declaration to the bridging header of your project:

@import UIKit;

@interface UINavigationController(PrivateMethods)

- (void)_startCustomTransition;

@end

Now, you can override the method without problems:

class MyNavigationController: UINavigationController {
    override func _startCustomTransition() {
        super._startCustomTransition()
    }
}

EDIT: You have to declare the method in an Objective-C extension, because I see no way to declare a method in a Swift extension without implementing it. Suggestions are very welcome. :)

clemens
  • 16,716
  • 11
  • 50
  • 65
  • Why bother with the whole objective C harder part and use swift extensions – CarpenterBlood Jul 21 '17 at 05:28
  • This should work with pure Swift, when you can declare a method without implementing it. – clemens Jul 21 '17 at 05:33
  • It does work was just wondering why you answered a swift question with Objective C code – CarpenterBlood Jul 21 '17 at 05:36
  • What should I do if my project doesn't have a bridging header file? It is a a pure Swift project. Ie, I selected Swift as my project's language when I created it. – ma11hew28 Aug 10 '17 at 11:16
  • What's the point of overriding a method just to call it's superclass's implementation? Won't you get the same functionality if you just don't override the method at all? – ma11hew28 Aug 10 '17 at 11:18
  • @ma11hew28: Xcode creates automatically a bridinging header, if you create an header oder Objective C file. Yes, I think the OP wanted to add additional code in the overridden method. ;) – clemens Aug 10 '17 at 14:22
  • I'm sorry. What is a header oder Objective-C file, and how do I create it in Xcode? – ma11hew28 Aug 10 '17 at 23:03
  • You say to add an Objective-C extension declaration, but the example code you provided contains an Objective-C category declaration. Which should it be? An [Objective-C extension or category](https://stackoverflow.com/questions/7136124/class-extension-vs-class-category)? – ma11hew28 Aug 10 '17 at 23:11
  • I think it should be a category, not an extension, because according to [Apple's Guides & Sample Code: Cocoa Core Competencies: Category](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Category.html), "You typically use a category to add methods to an existing class, such as one defined in the Cocoa frameworks," which I think is effectively what we want to do here. – ma11hew28 Aug 10 '17 at 23:55
  • When I added a new file using the "Objective-C File" template with "File Type" set to "Category," Xcode offered to create an Objective-C bridging header file for me, as described in [Apple's Guides & Sample Code: Using Swift with Cocoa and Objective-C: Swift and Objective-C in the Same Project](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html). – ma11hew28 Aug 10 '17 at 23:58
  • @ma11hew28: Categories and extensions in Objective C are almost the same. Extensions don't have an own implementation block. Extensions do not have their own implementation block, since they are implemented with the class. My suggestion doesn't need an implementation. – clemens Aug 11 '17 at 04:48
1

As of Swift 5.3 (and possibly older versions), the keyword "internal" provides the access level you are looking for.

override internal func f() {
    super.f()
}

See Access Control in the Swift Programming Language docs, at https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

Kevin Packard
  • 374
  • 4
  • 13