I'm fairly certain there is something obvious I am missing and/or doing incorrectly here.
I have a base class with a handleTapped() function that handles a button being tapped on.
In a subclass, I want to override that function but need to access the variables that I declare in the handleTapped() function in the parent class.
Ex:
class ParentClass {
#objc func handleTapped(sender: UITapGestureRecognizer) {
var a = [Int]()
var b = 10
if a[1] == b {
// do something
}
}
}
class SubClass: ParentClass {
#objc override func handleTapped(sender: UITapGestureRecognizer) {
super.handleTapped(sender: sender)
if a[1] == b {
// do something else
}
}
}
Variables declared in a function cannot be accessed from outside of that scope, including by methods that override their behaviour (unless you use them as a return of that function, which we can't do here).
In this case, you'll need to store the necessary information in the parent class itself, and make sure the access rights are set correctly (internal, or public depending on how your project is set up) so that the Subclass can access and modify that data.
Alternatively, there may be an alternative way to implement this. This might be a candidate where duplication of the code is a more preferable option to exposing data to all subclasses.
Take the variables out of the method and into the class like so:
class ParentClass {
var a = [Int]()
var b = 10
func handleTapped(sender: UITapGestureRecognizer) {
if a[1] == b {
// do something
}
}
}
class SubClass: ParentClass {
override func handleTapped(sender: UITapGestureRecognizer) {
super.handleTapped(sender: sender)
if a[1] == b {
// do something else
}
}
}
Related
This question already has answers here:
In Swift, how do I have a UIScrollView subclass that has an internal and external delegate?
(4 answers)
Closed 4 years ago.
Given a very simple protocol :
protocol TheProtocol {
func doSomething()
func doSomethingElse()
func doThis()
func doThat()
}
I have a class Base that has a delegate waiting to be set.
// Can't modify this class at all
class Base {
public var delegate: TheProtocol?
}
My second class B inherits from this class Base, and implements TheProtocol in order to set the delegate to itself.
class B: Base, TheProtocol {
override init() {
super.init()
self.delegate = self
}
func doSomething() {
}
func doSomethingElse() {
}
... other methods to implement
}
Now what I want to be able to do, is to have a last class C, that contains an instance of B, and also set the delegate. I want the delegate to work both inside B and C.
The major constraint is that I can't modify the Base class.
class C: TheProtocol {
var obj = B()
init() {
// If I do this it won't fire within B anymore
obj.delegate = self
}
func doSomething() {
}
func doSomethingElse() {
}
... other methods to implement
}
It is actually possible using a Proxy delegate. However not really recommended.
In Swift, how do I have a UIScrollView subclass that has an internal and external delegate?
ArtistVC is a subclass of CategoryVC which is a subclass of BrowserVC.
Most of ArtistVC's UITableView Data Source methods wind up calling CategoryVC's implementation of those methods with return super.tableView(tableView, cellForRowAt: adjustedIndexPath)(for example), after some other things happen of course, like modifying the indexPath passed to the method.
But sometimes I actually want to bypass CategoryVC's implementation and use BrowserVC's implementation.
super.super.someMethod() apparently isn't the answer. Is this possible?
There's a (convoluted) way to do this but it requires that the intermediate class "contributes" to the bypassing of its override.
For example:
class A
{
func doIt(_ parameter:Int) { print("A.doIt(\(parameter))") }
}
class B:A
{
override func doIt(_ parameter:Int) { print("B.doIt(\(parameter))") }
var super_doIt:(Int)->() { return super.doIt }
}
class C:B
{
override func doIt(_ parameter:Int)
{ super.super_doIt(parameter) }
}
let c = C()
c.doIt(3) // A.doIt(3)
I am working on a project in swift that involves multiple Swift files, each with a class in them. My goal is to have some classes that inherit properties from the others. For some reason, I cannot access any class' variables from any other class. For example, here is one file:
class Enemy {
var ready = false
var someVal = 0
func someFunctions() {
}
}
In another file, I've tried to create a class that inherits from "Enemy"
class badGuy: Enemy {
ready = true // This doesn't work as I would expect it to
func badGuyFunction() {
}
}
If I attempt to access the variables someVal or ready from either class, I am given an error;
class randomClass {
func test() {
print(Enemy.ready) //This doesn't work
print (badGuy.ready) // This doesn't work
}
}
What am I doing wrong here? I've tried to use init() functions in each of the classes, but that doesn't work. Just to clarify, I'd like to have a base class, then have a subclass whose "type" is the base class, then in the subclass define values for each of the variables the base class supports. badGuy should automatically be able to set it's own someVal. Thanks in advance.
You're very close. With just a few minor edits it works as you intend.
Here is the new Enemy class, which is almost identical to your original.
class Enemy {
var ready = false
var someVal = 0
func someFunction() {}
}
The BadGuy subclass can set its properties in its initializer.
class BadGuy: Enemy {
override init() {
super.init()
ready = true
}
func badGuyFunction() {}
}
And then you should be able to use them like this:
let badGuy = BadGuy()
print(badGuy.ready) // prints `true`
Issue #1 occurs because you have to override ready in the init method
class Enemy {
var ready = false
}
class BadGuy: Enemy {
override init() {
super.init()
ready = true
}
}
Stored properties cannot be overridden directly.
Issue #2 occurs because you are calling the instance method on the type. You need to create instances of the classes.
class RandomClass {
func test() {
let enemy = Enemy()
let badGuy = BadGuy()
print(enemy.ready)
print(badGuy.ready)
}
}
let randomClass = RandomClass()
randomClass.test() // prints two lines `false` and `true`
In my app I have one screen divided between two ViewControllers - LadderViewController and GameHistoryTableViewController, which lies in a container. I want user to be able to filter the data in the table by tapping on something in the LadderView. I tried to solve this using delegates:
LadderViewController:
delegate = GameHistoryTableViewController()
func imageTapped(imageIndex: Int) {
delegate?.selectedHeroNumber(imageIndex)
}
GameHistoryTableViewController: (conforms to the delegate protocol and implemets a function from it)
func selectedHeroNumber(heroNumber: Int) {
let filteredGames = filterGamesFromHeroNumber(heroNumber)
tableDataSource = filteredGames
self.tableView.reloadData()
}
That doesn't work, though, because the delegate I declare in LadderViewConroller is another instance of GameHistoryTableViewController, not the (to the user) shown one. I don't know how to access the "visible" instance (table) of GameHistoryTableViewController though... So, how should be delegating used here? Or should I use another approach (and if so, what kind)? I basically need to change the table's data source according to on what the user taps, one can say "from outside" (dataSource is a property in my GameHistoryTableViewController class).
Here is an example with delegation like you want to do. It's a better solution than singleton in this case ;)
declare a new protocol call HeroInfo:
protocol HeroInfo: class {
func selectedHeroNumber(heroNumber: Int);
}
LadderViewController:
//create the delegation
weak var delegate:HeroInfo?
func imageTapped(imageIndex: Int) {
//call the delegate method
delegate?.selectedHeroNumber(imageIndex)
}
GameHistoryTableViewController:
// Here get the protocol HeroInfo inheritance
class userTableViewController: UITableViewController, HeroInfo {
override func viewDidLoad() {
super.viewDidLoad()
//Here get your Ladder view in a splitView
if let split = self.splitViewController {
let controllers = split.viewControllers
self.ladderViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? ladderViewController
//register it to delegate
self.ladderViewController?.delegate = self
}
}
...
// Here is your method of your protocol that you must conform to
func selectedHeroNumber(heroNumber: Int) {
let filteredGames = filterGamesFromHeroNumber(heroNumber)
tableDataSource = filteredGames
self.tableView.reloadData()
}
...
}
There are a few ways to achieve this, I have a similar setup for which I use a model class with a singleton to store the relevant data.
For instance you could have the following
class dataModel {
static let sharedInstance = dataModel()
private var _heroNumber = Int()
private init() {}
var heroNumber: Int = {
return _heroNumber
}
func setHero(hero: Int) -> Int {
return _heroNumber
}
}
}
You can then can access this model from each of your controllers using dataModel.sharedInstance.heroNumber etc...
I want to define a method that can destroy the instance it belongs to when a variable in this class has increased to a certain value. I attempted to do something like following:
var calledTimes = 0 //some other method would update this value
func shouldDestroySelf(){
if calledTimes == MAX_TIMES {
denit
}
}
But i would get error message saying "Expect '{' for deinitializers".
Is there anyway to self-destruct within the class?
You can not call deinit method. From Apple Docs: Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself.
You should set that instance to nil in order to destroy that instance provided that all references to that instance are broken .
You can create a protocol which does the self destruction based on a certain criteria. Here's an example using a class
class SelfDestructorClass
{
var calledTimes = 0
let MAX_TIMES=5
static var instancesOfSelf = [SelfDestructorClass]()
init()
{
SelfDestructorClass.instancesOfSelf.append(self)
}
class func destroySelf(object:SelfDestructorClass)
{
instancesOfSelf = instancesOfSelf.filter {
$0 !== object
}
}
deinit {
print("Destroying instance of SelfDestructorClass")
}
func call() {
calledTimes += 1
print("called \(calledTimes)")
if calledTimes > MAX_TIMES {
SelfDestructorClass.destroySelf(self)
}
}
}
You can derive your class from this class and then call call() on those object. The basic idea is to have the ownership of the object at one and only one place only and then detach the ownership when the criteria is met. The ownership in this case is a static array and detaching is removing it from the array. One important thing to note is that you have to use weak reference to the object wherever you are using it.
E.g.
class ViewController: UIViewController {
weak var selfDestructingObject = SelfDestructorClass()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func countDown(sender:AnyObject?)
{
if selfDestructingObject != nil {
selfDestructingObject!.call()
} else {
print("object no longer exists")
}
}
}