Oscar
Oscar

Reputation: 2345

Why does the compiler claim CGRect has no width member?

Note that I'm not trying to set the value in a CGRect. I'm mystified as to why the compiler is issuing this claim:

let widthFactor = 0.8
let oldWidth = wholeFrameView.frame.width
let newWidth = wholeFrameView.frame.width * widthFactor // Value of type '(CGRect) -> CGRect' has no member 'width'
let newWidth2 = wholeFrameView.frame.width * 0.8  // This is fine.

Upvotes: 2

Views: 347

Answers (4)

user652038
user652038

Reputation:

Because, as others have noted, you can't multiply a Double and a CGFloat, the compiler doesn't know what you're intending.

So, instead of giving you an error about the frame property, which you currently think it's doing, it's actually making its best guess*, and giving you an error related to the frame method. No method method has a width property, so what it tells you is true.

*Of course, its best guess is not good enough, hence a human being coming here to ask a question about it. So please file a bug!

Stepping onto my soapbox: This confusion would be avoided if Apple hadn't named the method the thing it returns. The convention to prefix all such methods with get solves the problem. Some convention is important in any language with first-class functions, to disambiguate between properties and methods.

Upvotes: 1

Sweeper
Sweeper

Reputation: 271775

All the dimensions of a CGRect are of type CGFloat, not Double, and because Swift is especially strict about types, you can't multiply a CGFloat by a Double.

The interesting thing though, is that both CGFloat and Double implement ExpressibleByFloatLiteral. This means that 0.8, a "float literal", can be interpreted as either a Double or a CGFloat. Without context, it's always a Double, because of how the compiler is designed. Note that this only applies to float literals like 3.14, 3e8 etc, and not to identifiers of variables.

So the expression wholeFrameView.frame.width * 0.8 is valid because the compiler sees that width is a CGFloat, so it treats 0.8 as a CGFloat as well. No problems.

On the other hand, when you declare the variable widthFactor, it is automatically given the type Double, because there aren't any more context on that line to suggest to the compiler that you want it to be any other type.

This can be fixed by directly telling the compiler that you want widthFactor to be a CGFloat:

let widthFactor: CGFloat = 0.8

Upvotes: 2

Daniel Storm
Daniel Storm

Reputation: 18898

Width is a CGFloat where your multiplier is a Double. Explicitly declare the type of your multiplier:

let widthFactor: CGFloat = 0.8

Upvotes: 3

Gabe Spound
Gabe Spound

Reputation: 590

wholeFrameView.frame has no member width. Also, you need widthFactor to be of type CGFloat. Try:

let newWidth = wholeFrameView.frame.size.width * CGFloat(widthFactor)

Upvotes: -4

Related Questions