48

I'm trying to convert the following Objective-C code to Swift. In my Objective-C code, there's a static variable and its accessed from a class method.

@implementation SomeClass

static NSMutableArray *_items;

+ (void)someMethod {
    [_items removeAll];
}

@end

Since you can't access types declared like this private var items = [AnyObject]() from class functions in Swift, I created a stored property for it like this.

class var items: [AnyObject] {
    return [AnyObject]()
}

And I'm trying to call a method on it from a class function like so.

class func someFunction() {
    items.removeAll(keepCapacity: false)
}

But I get this error Immutable value of type '[AnyObject]' only has mutating members named 'removeAll'.

Can anyone please tell me what's the cause of this error and how to correct it?

Thank you.

Isuru
  • 30,617
  • 60
  • 187
  • 303

3 Answers3

77

With this code:

class var items: [AnyObject] {
    return [AnyObject]()
}

you are not creating a stored property - instead it's a computed property, and the worst part is that every time you access to it, a new instance of [AnyObject] is created, so whatever you add to it, it's lost as soon as its reference goes out of scope.

As for the error, the static computed property returns an immutable copy of the array that you create in its body, so you cannot use any of the array method declared as mutating - and removeAll is one of them. The reason why it is immutable is because you have defined a getter, but not a setter.

Currently Swift classes don't support static properties, but structs do - the workaround I often use is to define an inner struct:

class SomeClass {
    struct Static {
        static var items = [AnyObject]()
    }
}

SomeClass.Static.items.append("test")

If you want to get rid of the Static struct every time you refer to the items property, just define a wrapper computed property:

class var items: [AnyObject] {
    get { return Static.items }
    set { Static.items = newValue }
}

so that the property can be accessed more simply as:

SomeClass.items.append("test")
Antonio
  • 71,651
  • 11
  • 148
  • 165
  • 3
    Thanks for the response. I didn't like appending the struct name everywhere so I defined a computed property with the same name as the static property and access it through that. Got the idea from [here](http://stackoverflow.com/a/24924535/1077789). Is this okay? – Isuru Oct 25 '14 at 21:54
25

Updated to Swift1.2


In Swift1.2[Xcode6.3], you can declare static properties using keyword static, also you can declare static methods using keyword class or static.

class SomeClass {

    // use static modifier to declare static properties.
    static var items: [AnyObject]!

    // use class modifier to declare static methods.
    class func classMethod() {

        items.removeAll(keepCapacity: false)
    }

    // use static modifier to declare static methods.
    static func staticMethod() {

        items.removeAll(keepCapacity: false)
    }
}

EDIT:

The difference between static and class modifier is that static is just an alias for "class final",so methods modified with static can not be overridden in subclasses.

Thanks @Maiaux's

Steve Moser
  • 7,647
  • 5
  • 55
  • 94
tounaobun
  • 14,570
  • 9
  • 53
  • 75
  • 4
    It may be worth mentioning that the difference between "class func" and "static func" is that the former can be overridden in a subclass, so they're not exactly the same. From The Swift Programming Language: "Classes may also use the class keyword to allow subclasses to override the superclass’s implementation of that method". – Maiaux Apr 21 '15 at 23:15
  • 1
    I'll test this when I get home, but it's a good question to ask: Does Swift 1.2 support **class** properties? – Chris Marshall May 27 '15 at 20:14
  • 2
    @MAGNAWS Swift 1.2 does support **class** computed properties.However currently it does not support **class** stored properties yet. – tounaobun May 28 '15 at 00:30
  • @Benson Tommy Thanks! I figured that out when I got home. It's interesting they don't let us override properties, but they do let us override typealias, which I think is kinda cool for protocols. – Chris Marshall May 28 '15 at 11:02
1

Yet the manual for Swift 2 still claims just enumeration ond structures may use static store properities.

user1785898
  • 167
  • 1
  • 1
  • 7