I've got a superclass UIViewController class that implements a couple of default methods, e.g.:
class Super: UIViewController {
override func viewDidLoad () {
setupView()
}
func setupView () {
initToolbar()
setPageTitle()
}
func initToolbar () {
// some code..
}
func setPageTitle () {
// nothing?
}
}
and subclasses that inherit from Super:
class Sub: Super {
override func setPageTitle () {
self.title = "custom title"
}
}
I'd like to force all subclasses to override the setPageTitle() method (forcing a compile time error if no implementation is present). However, the only way I've managed to achieve this is providing a default implementation in the Super class that contains an assert statement, causing the app to crash if it has not been overriden. This is not really what I was after as the error is only present at runtime and ideally i'd like a compile time warning/error if the method has no implementation. Is there any way to set this method to be overriden as a requirement? Similar to abstract methods in other languages?
I thought about using protocols & extensions but it looks like with extensions I can't override the viewDidLoad method and this is necessary for the superclass.
Any ideas?
Related
I'm trying to implement Siri Shortcuts. To handle them I have to override the restoreUserActivityState function, but when I override it into my class which inherits from UIViewController, it results into this error: "Overriding 'restoreUserActivityState' must be as available as declaration it overrides". I tried to make my class and my function public but the error persists. Any idea how can I resolve this issue?
When you override a overridden method from a superclass, you make sure that, you are setting method in the subclass with higher access level than the superclass you inherit from. You can use open keyword.
Example:
class ViewController1: UIViewController {
override func restoreUserActivityState(_ activity:NSUserActivity) {
}
}
class ViewController2: ViewController1 {
open override func restoreUserActivityState(_ activity: NSUserActivity) {
}
}
I Hope, it solves your problem.
I want to extend UIView by adding some functions, and override them in any subclass of UIView that I want. I found in apple documentations that I can't override extensions (and the compiler will complain) which make some sense. So
I need someone to suggest an alternative way to the below:
extension UIView {
func hide() { //do almost nothing }
}
class myLabel: UILabel {
override func hide() {
//do work on uilabel that can't be done on imgView
}
}
class myImageView: UIImageView {
override func hide() {
//do work on imgView that can't be done on uilabel
}
}
And the reason I want this is that later in my code I will face the below code and I have to many subclasses and I don't want to write too many if-lets trying to cast the view to myLabel, myTextView, myImageView... etc
let view = cell.viewWithTag(someTag)
// and I want to write this below without casting
view.hide()
I tried with protocols and protocol extensions but I couldn't make it though.
Any thoughts?
Note: func hide() is just an example. My func will have more to do.
**Question updated to be clear.
EDIT: Updating answer to make use of protocols also
Protocols does in various ways enable to you replace subclassing in some cases however you still need your class to conform to the protocol to be able to see and override those methods
You can have a protocol for example:
protocol SomeProtocol {
func hide()
}
To do what you are intending to do it is best to have a parent subclass UIView with all functions that can be overridden for example (in this updated answer you can have your methods to override inside the protocol and have your subclasses conform to it):
class ParentView : UIView, SomeProtocol {
func hide() {
print("PARENT")
}
func anyOtherMethod() {
}
}
and then have all the other UIView's that need to override those methods subclass ParentView:
class ViewOne : ParentView {
override func hide() {
print("VIEW ONE")
}
}
class ViewTwo : ParentView {
override func hide() {
print("VIEW TWO")
}
}
So even if you later place this code:
let view = cell.viewWithTag(someTag)
// and I want to write this below without casting
view.hide()
you won't need to explicitly cast your UIView's, the view will call it's intended overridden method, unless and until you call super in your overridden method also
EDIT: More on making use of protocols
In the case you need other controls to also have a hide() method to override then you can still have to subclass, for example in the case of UILabel you need to override it:
class ParentLabel : UILabel, SomeProtocol {
func hide() {
print("PARENT LABEL")
}
}
then you can write the intended code with casting to your protocol
if let view = cell.viewWithTag(someTag) as? SomeProtocol {
view.hide() // prints PARENT LABEL
}
and either use that subclassed UILabel control or if you need in some cases some label to override that behavior then you can still create a child subclass of ParentLabel:
class LabelOne : ParentLabel {
override func hide() {
print("LABEL ONE")
}
}
I tried to create protocol which can be only implemented by classes which inherit from UIView, what was my surprise when this code compiles without errors (in Swift 3.0):
protocol TestsProtocol {
func test()
}
extension TestsProtocol where Self: UIView { }
class FooClass: TestsProtocol {
func test() {
}
}
We can see that FooClass don't inherit from UIView, using protocol extension I wan't to force that only classes which inherit from UIView can implement it.
As far as I remember this would not compile in Swift 2.1
You cannot do this in Swift. The extension syntax does something else:
extension TestsProtocol where Self: UIView {
func useful() {
// do something useful
}
}
now any class which implements TestsProtocol and is a UIView (or subclass) also has the useful() function.
You can do that easily by limit protocol from be extendable from any type other than UIView :
protocol TestsProtocol:UIView {
func test()
}
class FooClass: TestsProtocol {
func test() {
}
}
So this will cause compile error
'TestsProtocol' requires that 'FooClass' inherit from 'UIView'
class SuperClass
{
var delegate : SuperClassDelegate?
}
protocol SuperClassDelegate
{
func doFirstAction ()
func doSecondAction ()
}
class SubClass : SuperClass , SuperClassDelegate
{
override init ()
{
super.init()
self.delegate = self
}
func doFirstAction () {}
}
class MyViewController : UIViewController
{
override func viewDidLoad ()
{
let c : SubClass = SubClass()
}
func doSecondAction ()
{
// I want to handle this action in the ViewController
}
}
So I've made a subclass that, for convenience, can act as the superclass delegate. However some of the methods in the superclass delegate are still most appropriately implemented in a view controller, meaning I don't want my subclass to implement these.
Is there a better way I can be dealing with these delegates so I can 'share' the responsibility?
You could create a multicast delegate. That way multiple objects (the subclass, the ViewController) could be delegates from the caller object. The protocol methods would be optional and then you could choose which class would implement what methods from the protocol.
Alternatively you could just create 2 protocols with 2 delegate references in the caller object. Unless there would be some specific reason you want to use a single protocol.
When I look at UITableView, I find that UITableView 's UITableViewDelegate inherit from UIScrollViewDelegate in order to override UIScrollView's delegate
Here is how i implement my own subclass of 'UIScrollView'.
protocol UIFormViewDelegate:NSObjectProtocol, UIScrollViewDelegate{
}
class UIFormView: UIScrollView {
override var delegate:UIFormViewDelegate?
}
The problem is that the compiler gives a warning:
Property 'delegate' with type 'UIFormViewDelegate?' cannot override a property with type 'UIScrollViewDelegate?'
Can anybody tell me what's wrong here?
You cannot override the type of delegate
What you can do is something like that
class DelegateClass: NSObject, UIFormViewDelegate {
}
class UIFormView: UIScrollView {
func setUpDelegate() {
self.delegate = DelegateClass()
}
}
And then call the setUpDelegate from somewhere where it makes sense