192

I have the following class:

class ReportView: NSView {  
    var categoriesPerPage = [[Int]]()
    var numPages: Int = { return categoriesPerPage.count }
}

Compilation fails with the message:

Instance member 'categoriesPerPage' cannot be used on type 'ReportView'

What does this mean?

mfaani
  • 33,269
  • 19
  • 164
  • 293
Aderstedt
  • 6,301
  • 5
  • 28
  • 44
  • 12
    Guessing you're going to declare a computed property `numPages` rather than a closure delete the equal sign: `var numPages: Int { return categoriesPerPage.count }` – vadian Sep 02 '15 at 11:13
  • 2
    Can it please be explained more thoroughly exactly what this error message means? I am seeing it in a completely different context. – William Entriken Feb 03 '16 at 22:37
  • 2
    When you declare a block in the class scope, like above, you are limited to what is available in the type. You do not have access to any instance members. – Aderstedt Feb 06 '16 at 08:43
  • Note: The error message is similar to the one you get when trying to [create a lazy variable but forgot one of the requirements](http://stackoverflow.com/a/38252259/35690). In your case you don't want a lazy variable since `categoriesPerPage` is defined as `var` instead of `let`. – Senseful Jul 07 '16 at 18:02
  • 1
    Remove = from: var numPages: Int = – andrewz Aug 06 '17 at 22:59
  • I landed here using a struct. I was missing `static let` –  Jul 15 '18 at 02:04

8 Answers8

263

Sometimes Xcode when overrides methods adds class func instead of just func. Then in static method you can't see instance properties. It is very easy to overlook it. That was my case.

enter image description here

milczi
  • 7,064
  • 2
  • 27
  • 22
  • 6
    Ah thank you! Spent a long time figuring out why I wasn't getting any of the instance member autocomplete suggestions in Xcode. This seems like a bug, I'll file a radar with Apple – Apoorv Khatreja Jun 26 '20 at 14:37
  • 3
    Autocomplete screwed me too. This looks like a bug to me also. – Deitsch Sep 01 '20 at 12:22
  • 3
    This is actually not a bug. XCTesCase class has both Suite-level teardown method "open class func tearDown()" and instance method "open func tearDown()". And they are both available with autocompletion. – ViktoR Dec 27 '20 at 19:26
  • 2
    Thanks! I must be blind I did not see the word class. – Michael N Feb 09 '22 at 12:32
  • Freaking Xcode man! Such shit. – ravindu1024 Aug 09 '23 at 14:41
145

You just have syntax error when saying = {return self.someValue}. The = isn't needed.

Use :

var numPages: Int {
    get{
        return categoriesPerPage.count
    }

}

if you want get only you can write

var numPages: Int {
     return categoriesPerPage.count
}

with the first way you can also add observers as set willSet & didSet

var numPages: Int {
    get{
        return categoriesPerPage.count
    }
    set(v){
       self.categoriesPerPage = v
    }
}

allowing to use = operator as a setter

myObject.numPages = 5
Daniel Krom
  • 9,751
  • 3
  • 43
  • 44
63

For anyone else who stumbles on this make sure you're not attempting to modify the class rather than the instance! (unless you've declared the variable as static)

eg.

MyClass.variable = 'Foo' // WRONG! - Instance member 'variable' cannot be used on type 'MyClass'

instanceOfMyClass.variable = 'Foo' // Right!
Derek
  • 2,092
  • 1
  • 24
  • 38
  • 7
    This is the difference between `static` variable and `instance` variable, `MyClass.variable` is valid if you'll declare it as static variable (shared between all instances) – Daniel Krom Jul 10 '16 at 14:56
  • This was my problem. I find it kind of odd when XCode decides to put the class first in the autocomplete options before a similarly-named instance when the context seems to point to me definitely using the instance rather than the class itself. And in cases where your instance only differs by case, it can be hard to notice you chose the class rather than the instance you meant to. Thanks! – LeftOnTheMoon Jun 13 '20 at 21:30
30

It is saying you have an instance variable (the var is only visible/accessible when you have an instance of that class) and you are trying to use it in the context of a static scope (class method).

You can make your instance variable a class variable by adding static/class attribute.

You instantiate an instance of your class and call the instance method on that variable.

Vlad
  • 5,727
  • 3
  • 38
  • 59
  • In my case, I tried to use an instance variable in the completion block called after an instance of another class had been initialised. Of course, an init is a class function, and declaring the instance variable as static solved the problem. – Reinhard Männer Jun 05 '19 at 12:14
10

Another example is, you have class like :

@obc class Album: NSObject {
    let name:String
    let singer:Singer
    let artwork:URL
    let playingSong:Song


    // ...

    class func getCurrentlyPlayingSongLyric(duration: Int = 0) -> String {
        // ...
       return playingSong.lyric
    }
}

you will also get the same type of error like :

instance member x cannot be used on type x. 

It's because you assign your method with "class" keyword (which makes your method a type method) and using like :

Album.getCurrentlyPlayingSongLyric(duration: 5)

but who set the playingSong variable before? Ok. You shouldn't use class keyword for that case :

 // ...

 func getCurrentlyPlayingSongLyric(duration: Int = 0) -> String {
        // ...
       return playingSong.lyric
 }

 // ...

Now you're free to go.

MGY
  • 7,245
  • 5
  • 41
  • 74
5

Your initial problem was:

class ReportView: NSView {
  var categoriesPerPage = [[Int]]()
  var numPages: Int = { return categoriesPerPage.count }
}

Instance member 'categoriesPerPage' cannot be used on type 'ReportView'

previous posts correctly point out, if you want a computed property, the = sign is errant.

Additional possibility for error:

If your intent was to "Setting a Default Property Value with a Closure or Function", you need only slightly change it as well. (Note: this example was obviously not intended to do that)

class ReportView: NSView {
  var categoriesPerPage = [[Int]]()
  var numPages: Int = { return categoriesPerPage.count }()
}

Instead of removing the =, we add () to denote a default initialization closure. (This can be useful when initializing UI code, to keep it all in one place.)

However, the exact same error occurs:

Instance member 'categoriesPerPage' cannot be used on type 'ReportView'

The problem is trying to initialize one property with the value of another. One solution is to make the initializer lazy. It will not be executed until the value is accessed.

class ReportView: NSView {
  var categoriesPerPage = [[Int]]()
  lazy var numPages: Int = { return categoriesPerPage.count }()
}

now the compiler is happy!

bshirley
  • 8,217
  • 1
  • 37
  • 43
0

I kept getting the same error inspite of making the variable static. Solution: Clean Build, Clean Derived Data, Restart Xcode. Or shortcut Cmd + Shift+Alt+K

UserNotificationCenterWrapper.delegate = self

public static var delegate: UNUserNotificationCenterDelegate? {
        get {
            return UNUserNotificationCenter.current().delegate
        }
        set {
            UNUserNotificationCenter.current().delegate = newValue
        }
    }
Naishta
  • 11,885
  • 4
  • 72
  • 54
0

Just in case someone really needs a closure like that, it can be done in the following way:

var categoriesPerPage = [[Int]]()
var numPagesClosure: ()->Int {
    return {
        return self.categoriesPerPage.count
    }
}
algrid
  • 5,600
  • 3
  • 34
  • 37