Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I set the speed of a GKAgent2D in iOS9?

Tags:

ios

gamekit

If I try to change the value of the speed parameter of a GKAgent2D (or its parent class GKAgent) in iOS9 I get this unrecognised selector error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GKAgent2D setSpeed:]: unrecognized selector sent to instance

However in iOS10 this error does not occur and the speed of the agent is changed correctly.

I can reproduce the error in a very simple example (single view iOS application, change the view controller code to the following, note that the error occurs with either GKAgent2D or GKAgent):

import UIKit
import GameplayKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var agent = GKAgent()
        agent.speed = 10

        print(agent.speed)
    }

}

The above always crashes with this unrecognised selector error on the line that sets the agent's speed on the simulator running iOS9.3, but not iOS10.3 (all this under Xcode 8.3.2).

The speed property of GKAgent is documented as being read and write and being supported under iOS9 - see Apple's Documentation for GKAgent, speed Property.

I had a similar problem with GKAgentDelegate, which would crash on iOS9 only with an unrecognised selector to agentWillUpdate. I worked around this by putting a dummy method in my code:

func agentWillUpdate(_ agent: GKAgent) {
}

I have tried a similar solution to the new error, by overriding the speed property in my GKAgent2D sub class and providing an explicit setter and getter, and even backing the speed parameter by a private Float as suggested by Kdawg, but the same error still occurs when the super's speed parameter is set:

class Agent:GKAgent2D {
    override var speed:Float {
        get {return localSpeed}
        set {localSpeed = newValue}
    }
    private var localSpeed:Float {
        get {return super.speed}
        set {super.speed = newValue}
    }
}

Any thoughts?

Specifically: are there any known issues with GKAgent in iOS9 regarding selectors?

Alternatively, any thoughts on an alternative work around?

I would like to support iOS9 if I can. It looks to me like a bug in GameplayKit - but I expect Apple's response to a report would be that it is fixed in iOS10.

like image 450
Ali Beadle Avatar asked Jul 08 '17 20:07

Ali Beadle


1 Answers

Edited

What I meant was to have your subclass's property setter/getter just override the base class's and not try to access the parent class's setter at all, like this:

class Agent:GKAgent2D {
    private var _speed: Float = 0.0 
    override var speed:Float {
        get {return _speed}
        set {_speed = newValue}
    }
}

At that point, assuming that the GKAgent and GKAgent2d accesses speed through its property getter, it will get the value of _speed from the overridden getter in your subclass. This is why I suggested in the comments to try this after making that subclass:

var agent: GKAgent 
agent = GKAgent2dSubType()
agent.speed = 10

I would then expect that if you then tried to read out the property of your GKAgent agent, it would be 10. And so the expected behavior of your agent might work properly with your speed in there.


Original This is just a total guess (I'm not really familiar with the technologies here), but have you tried changing your

override var speed:Float {
    get {return super.speed}
    set {self.speed = newValue}
}

to not reference super.speed or self.speed (incidentally, shouldn't setting self.speed from your speed setter result in an infinite recursive call to that setter?) but rather to reference a private backing floating point value? Then maybe you'll be able to instantiate an object of type GKAgent2dSubClass (however you've named that subclass) and have it work.

like image 194
Kdawg Avatar answered Sep 17 '22 14:09

Kdawg