11

A simple Swift class has a field of type var Array. When the class is adapted to Objective-C the field type is exposed as NSArray (immutable) while it should be NSMutableArray (mutable)

class Categoryy: NSObject {

    var items = Array<Item>()

}

The Categoryy swift class is adapted to Objective-C in the Xcode-generated header MODULE_NAME-swift.h file as following:

SWIFT_CLASS("_TtC8waiterio9Categoryy")
@interface Categoryy : NSObject
@property (nonatomic, copy) NSArray * items;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

is there a way for the var items : Array field to be converted to a mutable NSMutableArray in Objective-c?

3
  • You aren't able to change the header to NSMutableArray? Commented Sep 19, 2014 at 12:16
  • it isn't a feasible solution :( The Xcode-generated header for Swift named MODULE-swift.h is erased and recreated by Xcode each time one of the swift files changes a field or method signature. You can change manually the type of fields from NSArray to NSMutableArray but as soon as you change a swift file's fields or methods' signature all your changes are lost. Commented Sep 21, 2014 at 11:59
  • Did you file a radar on this? Commented Sep 23, 2014 at 7:15

3 Answers 3

6
+25

That is because items property is actually immutable.

As you know, because of the nature of struct based implementation of Array in Swift, following code does not affect cat.items.

let cat = Categoryy()

var _items = cat.items
_items.append(item)

Instead, you have to call like this

cat.items.append(item)

On the other hand, in Objective-C, [cat.items addObject:item] is exactly same as following:

id _items = [cat items];
[_items addObject:item];

That is very similar to non-working Swift code.

Sad to say, Objective-C does not have equivalent property/method calling semantics as cat.items.append(item) in Swift.

This is similar to:

// Objective-C
CGRect frame = view.frame;
view.frame = CGRectMake(frame.origin.x, 50, frame.size.width, frame.size.height)

// Swift
view.frame.origin.y = 50

--

Maybe Apple can implement that as NSMutableArray(or private subclass), of course you can request that. I doubt Apple will do that, because that breaks compile time type safety by Generics.

Anyway, I think, you should implement Categoryy like this:

class Categoryy: NSObject {
    var items:[Item] = []

    func addItem(item:Item) {
        items.append(item)
    }

    func setItem(item:Item, atIndex:Int) {
        items[atIndex] = item;
    }

    // and so on ..
}
Sign up to request clarification or add additional context in comments.

Comments

1

If you want an NSMutableArray, the easiest way is to just use an NSMutableArray in Swift. Array<T> doesn't (and couldn't) both behave as (an immutable) NSArray and NSMutableArray at the same time - right now, what it does behave as is as an immutable NSArray. Swift could use a built-in class type that corresponds to NSMutableArray the way Array<T> corresponds to NSArray though.

Another alternative is to use a Swift class wrapping an NSMutableArray with @objc exposed methods to access the NSMutableArray. That also lets you use generics to constrain items to T.

Comments

0

As a workaround, you could call append in the Swift file using a method, instead of accessing the Swift array directly in Objective-C.

Swift:

func addItem(item:Item)
{
    items.append(item)
}

Objective-C:

[yourSwiftObject addItem:item];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.