5

I am trying to use the #keyPath syntax in order to get a CALayer property to animate it like this:

let myAnimation = CABasicAnimation.init(keyPath: #keyPath(CALayer.position.x))

and I get the following error:

Type 'CGPoint' has no member 'x'

What am I missing?

TheoK
  • 3,601
  • 5
  • 27
  • 37

2 Answers2

5

The #keyPath directive expects an Objective-C property sequence as argument. CALayer inherits from NSObject, but its position property is struct CGPoint, which is not a class at all, and cannot used with Key-Value coding.

However, CALayer has a special implementation of value(forKeyPath:) which handles the entire key path, instead of evaluating the first key and passing down the remaining key path, compare KVC strange behavior.

So Key-Value Coding can be used with "position.x", but the compiler does not know about this special treatment. As an example, this all compiles and runs:

let layer = CALayer()
layer.position = CGPoint(x: 4, y: 5)

print(layer.value(forKeyPath: "position"))   // Optional(NSPoint: {4, 5}
print(layer.value(forKeyPath: "position.x")) // Optional(4)

print(layer.value(forKeyPath: #keyPath(CALayer.position))) // Optional(NSPoint: {4, 5})

but this does not compile:

print(layer.value(forKeyPath: #keyPath(CALayer.position.x)))
// error: Type 'CGPoint' has no member 'x'

That is the reason why

let myAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.position.x))

does not compile, but this does (as Reinier Melian suggested):

let myAnimation = CABasicAnimation(keyPath: "position.x")
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
1

position is a property in object of type CALayer and you want to access it from base class , second keyPath takes a property to animate in the layer and CALayer.position.x is not a property inside CALayer object that you want to animate , so it must be position.x that you can't write directly without string "" as you will have error saying can't find position in the class you want to declare it in , so proper way would be like this

  let myLayer = CALayer.init()
  myLayer.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
  let anim =  CABasicAnimation.init(keyPath: "position.x")
  anim.fromValue = 20
  anim.toValue = 100
  anim.duration = 1
  myLayer.add(myAnimation, forKey: "position.x")
  self.view.layer.addSublayer(myLayer)
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • I know this alternative. The question is why the #keyPath syntax in this instance is returning this error. – TheoK Feb 24 '18 at 15:41
  • can you edit your original answer, so that it reflects the actual question? – TheoK Feb 24 '18 at 15:54