Swift override instance variables
As you say, you cannot simply redefine a constant in a subclass (it is a constant, after all). The error you get is "Cannot override with a stored property". It does appear to be possible to override a var
, however, when I change the let someVariable
to var someVariable
I get "ambiguous use of 'someVariable'" when I access it in the subclass (note - same thing happens whether I use override
or not).
The simplest solution is to use a getter. This is really a function, so you can happily override it, the backing variable will be managed for you, and if you don't supply a setter ... it will be constant for each class:
class BaseView: UIView {
var someVariable: Int { get { return 1 } }
// do some work with someVariable
}
class ExtendedView: BaseView {
override var someVariable: Int { get { return 2 } }
}
let a = BaseView()
a.someVariable // 1
let b = ExtendedView()
b.someVariable // 2
As commentator @user3633673 points out, if you only have a getter (and not a setter), you can drop the get
, but I left it in for clarity of the principle. Here's the same without it...
class BaseView: UIView {
var someVariable: Int { return 1 }
// do some work with someVariable
}
class ExtendedView: BaseView {
override var someVariable: Int { return 2 }
}
let a = BaseView()
a.someVariable // 1
let b = ExtendedView()
b.someVariable // 2
... and, of course, in Swift 5, you can drop the return
:
class BaseView: UIView {
var someVariable: Int { 1 }
}
class ExtendedView: BaseView {
override var someVariable: Int { 2 }
}
Swift Unable to Override Variables in Subclass
EDIT
@Knight0fDragon was right, a better approach is to use super.texture
class classTwo: classOne {
override var texture:SKTexture? {
get {
return super.texture
}
set {
super.texture = newValue
}
}
}
In order to override the property you need to initialise it. In other words, giving it an initial value. If you don't want, here is a workaround:
class classTwo: classOne {
var _texture:SKTexture
override public var texture: SKTexture? {
get {
return _texture
}
set {
_texture = newValue!
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Some other functions
}
Overriding default value of instance var
Define an init()
method as:
init () {
super.init()
x = "y"
}
You'll want any other initializers in Obj1
to invoke this as self.init()
. The Apple documentation has a long discussion on designated initializers and inheritance vis-a-vis initializers.
Overriding a stored property in Swift
Why am I not allowed to just give it another value?
You are definitely allowed to give an inherited property a different value. You can do it if you initialize the property in a constructor that takes that initial value, and pass a different value from the derived class:
class Jedi {
// I made lightSaberColor read-only; you can make it writable if you prefer.
let lightSaberColor : String
init(_ lsc : String = "Blue") {
lightSaberColor = lsc;
}
}
class Sith : Jedi {
init() {
super.init("Red")
}
}
let j1 = Jedi()
let j2 = Sith()
print(j1.lightSaberColor)
print(j2.lightSaberColor)
Overriding a property is not the same as giving it a new value - it is more like giving a class a different property. In fact, that is what happens when you override a computed property: the code that computes the property in the base class is replaced by code that computes the override for that property in the derived class.
[Is it] possible to override the actual stored property, i.e.
lightSaberColor
that has some other behavior?
Apart from observers, stored properties do not have behavior, so there is really nothing there to override. Giving the property a different value is possible through the mechanism described above. This does exactly what the example in the question is trying to achieve, with a different syntax.
Protected variable in an objective c super class is inaccessible in a swift subclass
As Alexander Explained in his answer, this is not "straightforwardly" achievable.
Since I'm not willing to alter the objective C super class, I decided to depend on KVC to achieve what I need.
(value(forKey: "thisStringIsInaccessibleInSwiftSubclasses") as! NSString)//you now have access to the @protected instance variable
I'll then create a main swift class and do all the KVC work in it.
Updating an instance variable for an object from another class in Swift
This is the first viewController:
class ViewController: UIViewController, ViewControllerSecondDelegate {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Next" {
let vc = segue.destination as? ViewControllerSecond
vc?.delegate = self
}
}
func secondDelegate(_ value: Bool) {
print("delegate") //needUpdating = value
}
}
and this is the secondViewController:
protocol ViewControllerSecondDelegate {
func secondDelegate(_ value: Bool)
}
class ViewControllerSecond: UIViewController {
weak var delegate: ViewControllerSecondDelegate?
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
delegate?.secondDelegate(true) //call this wherever you need it.
}
}
Initialize instance variables inside instance function
This occurs because
var someVar: Footer!
does not define a variable of type Footer
but a variable of type Optional<Footer>
that is implicitly unwrapped. The code:
var someFooter: Footer!
bind(footer: &someFooter)
is logically equivalent to
var someFooter: Footer?
guard let tempFooter = someFooter? else { fatalError() }
bind(footer: &tempFooter)
As you can see, tempFooter
is a let, so it can't be passed as an inout variable and even if it could, the result would be thrown away.
You can fix this in one of three ways:
make the parameter to bind an optional, e.g.
func bind(footer: inout Footer?)
or use Martin's syntax to make it implicitly optional.Force the unwrap yourself:
var unwrapped: Footer = someFooter
bind(footer: unwrapped)
someFooter = unwrappedredesign the API. It seems the first thing you do in the
bind
function is overwrite the old footer with a newly initialised footer. So don't use an inout parameter, return the value you want i.e.func bind() -> Footer
{
var theFooter = Footer(...) { ... }
// do stuff
return theFooter
}
someFooter = bind()
I think the last option is the best in this case.
If I subclass a class, can I specify a certain subclass an instance variable should be?
How about using generic? For simplicity, I removed NSObject
class MyObject {
}
class MyObjectA: MyObject {
}
class MyObjectB: MyObject {
}
class BaseClass<T> where T : MyObject {
var myObject: T?
}
class SubClassA: BaseClass<MyObjectA> {
}
class SubClassB: BaseClass<MyObjectB> {
}
Related Topics
Uitableview Dynamic Cell Heights Only Correct After Some Scrolling
How to Make View the Size of Another View in Swiftui
How to Attach Debugger to iOS App After Launch
Check If Uicolor Is Dark or Bright
Usage of Protocols as Array Types and Function Parameters in Swift
How to Disable/Enable the Sleep Mode Programmatically in iOS
Since Xcode 8 and iOS10, Views Are Not Sized Properly on Viewdidlayoutsubviews
How to Create a Simple Checkbox in iOS
Objective-C 101 (Retain VS Assign) Nsstring
Using Custom Font in a Uiwebview
Why Is Uitextfield.Text an Optional
Cannot Use Instance Member Within Property Initializer
Amazon Aws iOS Sdk: How to List All File Names in a Folder
Negative Number Modulo in Swift
How to Create a Hex Color String Uicolor Initializer in Swift
Install Apps on Device Without Itunes
Rebuild an Nsarray by Grouping Objects That Have Matching Id Numbers