0

I have a NSMutable Array in swift which contains the inner array respective to the key like this.

Array Sample:
{
    Item =         (
        Studio,
        "1 bed",
        "2 bed",
        "3 bed",
        "4 bed",
        "5+ bed",
        "Individual Lease"
    );
    Status =         (
        None,
        None,
        None,
        None,
        None,
        None,
        None
    );
},
    {
    Item =         (
        "1+ bath",
        "2+ bath",
        "3+ bath",
        "4+ bath"
    );
    Status =         (
        None,
        None,
        None,
        None
    );
},
    {
    Item =         (
        "On Campus",
        "Off Campus",
        "Downtowm Lafayette",
        Lafayette
    );
    Status =         (
        None,
        None,
        None,
        None
    );
}

Code is:

var itemsArray = NSMutableArray()
var itemArr1:[String] = "Studio,1 bed,2 bed,3 bed,4 bed,5+ bed,Individual Lease".componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: ","))
var statusArr1:[String] = "None,None,None,None,None,None,None".componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: ","))

var itemArr2:[String] = "1+ bath,2+ bath,3+ bath,4+ bath".componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: ","))
var statusArr2:[String] = "None,None,None,None".componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: ","))

var itemArr3:[String] = "On Campus,Off Campus,Downtowm Lafayette,Lafayette".componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: ","))
var statusArr3:[String] = "None,None,None,None".componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: ","))


itemsArray.insertObject(["Item": itemArr1, "Status": statusArr1], atIndex: 0)
itemsArray.insertObject(["Item": itemArr2, "Status": statusArr2], atIndex: 1)
itemsArray.insertObject(["Item": itemArr3, "Status": statusArr3], atIndex: 2)



println("\(itemsArray)")

itemsArray.objectAtIndex(0).valueForKey("Item").replaceObjectAtIndex(0, withObject: "ReplaceValue")

Now When I am going to replace any index status or like key array value then it is crashing. In short i need to replace the value of any index of nested array. Same patterns works nice in objective c. If you have any idea or code related to these type then please help me. Your help will be admirable. Thanks a lot in Advance.

2 Answers 2

2

I suspect that the problem here is the way in which you are mixing native Swift types with Objective-C types. If your code really reflects your desired data structure, why not use all native Swift types? Then what you want to do becomes pretty simple:

var itemsArray = [Dictionary<String, [String]>]()

var itemArr1: [String] = "Studio,1 bed,2 bed,3 bed,4 bed,5+ bed,Individual Lease".componentsSeparatedByString(",")
var statusArr1: [String] = "None,None,None,None,None,None,None".componentsSeparatedByString(",")
var itemArr2: [String] = "1+ bath,2+ bath,3+ bath,4+ bath".componentsSeparatedByString(",")
var statusArr2: [String] = "None,None,None,None".componentsSeparatedByString(",")

var itemArr3: [String] = "On Campus,Off Campus,Downtowm Lafayette,Lafayette".componentsSeparatedByString(",")
var statusArr3: [String] = "None,None,None,None".componentsSeparatedByString(",")


itemsArray.append(["Item": itemArr1, "Status": statusArr1])
itemsArray.append(["Item": itemArr2, "Status": statusArr2])
itemsArray.append(["Item": itemArr3, "Status": statusArr3])

println("\(itemsArray)")

itemsArray[0]["Item"]![0] = "ReplaceValue"

itemsArray is now a fully native Swift data structure -- an array of dictionaries, where each dictionary maps a string to an array of strings. To change a value, just assign it.

Update

As for the specific reason that your code wasn't working, I'll confess that I find it a bit murky. Let's look at the failing line again:

itemsArray.objectAtIndex(0).valueForKey("Item").replaceObjectAtIndex(0, withObject: "ReplaceValue")

And here it is broken down by each call, showing the type returned by each call:

itemsArray             // NSMutableArray
  .objectAtIndex(0)    // AnyObject
  .valueForKey("Item") // AnyObject
  .replaceObjectAtIndex(0, withObject: "ReplaceValue") // Blows up

The interesting thing here is the way that Swift is implicitly downcasting those AnyObjects. Recall that the NSArray/NSDictionary/etc have contents that are un-typed, so accessing them returns a generic AnyObject that you can try to downcast into more specific types.

In the first case, Swift is handling this for you automatically, downcasting the AnyObject returned by ObjectAtIndex into an NSDictionary so you can call valueForKey on it.

In the second case, however, it is unwilling to downcast the AnyObject into an NSMutableArray so you can call replaceObjectAtIndex. Why the difference between these two cases?

I'm not sure. But it seems that Swift is unwilling to downcast to the Mutable flavor of Objective-C collections from their Swift counterparts. The object that you supplied in this case was a Swift Array (an Array<String> to be precise). Even though this object was declared as var, Swift refuses to allow the object to go from Array<String> to AnyObject to NSMutableArray.

You can see this pretty easily yourself by trying the following:

var test_array = ["hello", "there"]
(test_array as AnyObject) as NSArray  // works
(test_array as AnyObject) as NSMutableArray // blows up

For me, the moral of the story here is don't use the NS collection types from Swift unless you have to. And when you do use them in Swift code, make sure that you know the types of the objects going in and out of them and be careful of Swift's being good-natured about trying to smooth away the difference between the native Swift collection types and their Objective-C counterparts.

Sign up to request clarification or add additional context in comments.

3 Comments

sir the way you did it is working fine but my question still is that the way i did, wasn't correct if yes then what was the problem..
I've added some more content to respond to your question.
Now i got sir Thanks you very much
0

So why it is crashing is that you are trying to call replaceObjectAtIndex on a Swift array, not an NSMutableArray.

Add this code after println("\(itemsArray)")

let isArray = itemsArray.objectAtIndex(0).valueForKey("Item") is Array<String>
let isMutableArray = itemsArray.objectAtIndex(0).valueForKey("Item") is NSMutableArray

println("Results \(isArray) and \(isMutableArray)")

And you should see the output "Results true and false"

The reason why Todd Agulnick's code works since he converted it to use all Swift data types and the compiler can infer all the types. For you to have your code work, you'd also need to properly type cast the components using as? or let.

As a suggestion, as you are learning Swift, you may want to not build these longer chained statements but break them down. It is more code, however, it will add more clarity as you learn, as you will better understand what each part does.

1 Comment

I think he's actually calling replaceObjectIndex on an AnyObject. The compiler seems to think that it can perform the downcast to an NSMutableArray but the code it generates crashes at runtime.

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.