How to cast a swift array of tuples to NSMutableArray? - arrays

I have swift array of tuples [(String, String)] and would like to cast this array to NSMutableArray. I have tried this and it is not working:
let myNSMUtableArray = swiftArrayOfTuples as! AnyObject as! NSMutableArray

Since swift types like Tuple or Struct have no equivalent in Objective-C they can not be cast to or referenced as AnyObject which NSArray and NSMutableArray constrain their element types to.
The next best thing if you must return an NSMutableArray from a swift Array of tuples might be returning an Array of 2 element Arrays:
let itemsTuple = [("Pheonix Down", "Potion"), ("Elixer", "Turbo Ether")]
let itemsArray = itemsTuple.map { [$0.0, $0.1] }
let mutableItems = NSMutableArray(array: itemsArray)

There are two problems with what you are trying to do:
Swift array can be cast to NSArray, but it cannot be cast to NSMutableArray without constructing a copy
Swift tuples have no Cocoa counterpart, so you cannot cast them or Swift collections containing them to Cocoa types.
Here is how you construct NSMutableArray from a Swift array of String objects:
var arr = ["a"]
arr.append("b")
let mutable = (arr as AnyObject as! NSArray).mutableCopy()
mutable.addObject("c")
print(mutable)

Related

Type Any?! has no subscript member in swift 3

I have problem with converting a code into swift 3.0 from 2.3.
Here is the my code for swift 2.3
var RequestDict = [String: AnyObject]()
func API() {
self.RequestDict = result["rows"]![0]["value"] as! [String: AnyObject]
}
This code working fine in swift 2.3 but 3.0 its displaying error.
Type Any?! has no subscript member.
Earlier the code in swift 2.3 result["rows"]![0] was easily compiled without errors. But things have changed in swift 3 as the resultant is converted to Any type and Any type has no subscript members.
result["rows"] should be first typecasted in Array and then from that array you can access the 0th element which needs to be further typecasted in the type which you are receiving.
If you want the above code to work like before, then you can use SwiftyJSON where you can convert your result into a JSON object
Assuming your result is an object which has an array named as rows inside.
let dictionary = result as! [String:AnyObject]
let yourResultInJSON = JSON(rawValue: dictionary)
Then you can easily use this line yourResultInJSON["rows"]![0]["value"] which will also be a new JSON object where you can fetch your desired key values like:
let finalValue = yourResultInJSON["rows"]![0]["value"]
let someValue = finalValue["yourKey"].stringValue //or intValue or whatever you need to typecast

Access items from an Array that is inside a Dictionary in Swift

I have a Dictionary which contains an array of fruits and a Double. What I would like to be able to do is access the fruits inside the array.
How can I access items inside the fruits array?
var fruits = ["Apple", "Oranges"]
var fruitDictionary:[String: Any] = ["fruits":fruits, "car":2.5]
print("Dictionary: \(fruitDictionary["fruits"]!)") // output: Dictionary: ["Apple", "Oranges"]
I tried...
print("Dictionary: \(fruitDictionary["fruits"[0]]!)")
and...
print("Dictionary: \(fruitDictionary["fruits[0]"]!)")
But no luck
Thanks
First you need to access the fruits entry of the dictionary and cast it as an array of strings.
From there you can access the elements of the array.
if let array = fruitDictionary["fruits"] as? [String] {
print(array[0])
}
The reason why your attempts did not work is because the values in your dictionary are of type Any, which might not be able to be accessed through a subscript.

addObjectsFromArray to the beginning of an existing array

I'm having trouble adding an existing array to the beginning of another array.
For example:
MutableID array contains 1,2,3,4,5 & idArray array contains 6,7,8
self.MutableID.addObjectsFromArray(idArray as [AnyObject])
//currently puts values to the end of the array not the beginning
this code outputs 1,2,3,4,5,6,7,8 but I want it to output 6,7,8,1,2,3,4,5
I need the values added to the beginning of self.MutableID Any suggestions on how I can accomplish this?
NSMutableArray has insertObjects method.
self.MutableID.insertObjects(otherArray as [AnyObject], atIndexes: NSIndexSet(indexesInRange: NSMakeRange(0, otherArray.count)))
Or you can assign the mutable array to a swift array and use insertContentsOf method ;)
self.MutableID = NSMutableArray(array: [1,2,3,4])
var otherArray = NSMutableArray(array: [6,7,8,9])
var swiftArr : [AnyObject] = self.MutableID as [AnyObject]
swiftArr.insertContentsOf(otherArray as [AnyObject], at: 0)
self.MutableID.insertContentsOf(idArray as [AnyObject], at: 0)
This question is the Swift version of this question which solves the problem in Objective-C.
If we must, for whatever reason, be using Objective-C's NSArray or NSMutableArray, then we can simply use a Swift translation of the code in my answer over there:
let range = NSMakeRange(0, newArray.count)
let indexes = NSIndexSet(indexesInRange: range)
oldArray.insertObjects(newArray as [AnyObject], atIndexes: indexes)
Where oldArray is an NSMutableArray and newArray is NSArray or NSMutableArray.
Or the other approach, append and reassign:
oldArray = newArray.arrayByAddingObjectsFromArray(oldArray as [AnyObject])
But the most correct thing to do would be to use the Swift Array type, and then use the insertContentsOf(_: Array, at: Int) method, as fluidsonic's answer describes.

2D empty array ( String and Bool) in swift

I see some questions for multidimensional arrays and two dimensional arrays but none of them show how to correctly implement an empty array.
I have a todo list where I have a checkbox in the cell. Currently I'm storing the todo item in an array and the bool value in another array...My app is starting to get big so I'd prefer to have them both in one array.
How do I correctly do it?
var cellitemcontent = [String:Bool]()
if this is the correct way then I get errors at
cellitemcontent.append(item) //String: Bool does not have a member named append
So I'm assuming this is how to declare a Dictionary not a 2D array...
Also how would I store a 2D array? When it's 1D I store it like this:
NSUserDefaults.standardUserDefaults().setObject(cellitemcontent, forKey: "cellitemcontent") // Type '[(name: String, checked: Bool)]' does not conform to protocol 'AnyObject'
You can create an array of tuples as follow:
var cellitemcontent:[(name:String,checked:Bool)] = []
cellitemcontent.append(name: "Anything",checked: true)
cellitemcontent[0].name // Anything
cellitemcontent[0].checked // true
If you need to store it using user defaults you can use a subarray instead of a tuple as follow:
var cellitemcontent:[[AnyObject]] = []
cellitemcontent.append(["Anything", true])
cellitemcontent[0][0] as String // Anything
cellitemcontent[0][1] as Bool // true
NSUserDefaults().setObject(cellitemcontent, forKey: "myArray")
let myLoadedArray = NSUserDefaults().arrayForKey("myArray") as? [[AnyObject]] ?? []
myLoadedArray[0][0] as String
myLoadedArray[0][1] as Bool

Unwrap Sparse Array in Swift

I'd like to write an extension for Array which safely returns an unwrapped version of itself.
I can do it with a generic method like so:
func unwrapElements<T>(array: [T?]) -> [T] {
let filtered: [T?] = array.filter{ $0 != nil }
let unwrapped: [T] = filtered.map { $0! }
return unwrapped
}
And I can call it like this:
let sparseNames: [String?] = ["alice", "bob", nil, "doug", nil, nil, "george", "hubert"]
let names: [String] = unwrapElements(sparseNames)
where names ends up being ["alice", "bob", "doug", "george", "hubert"] and is safe to iterate and work with each element.
However, I want to call it like this:
let names = sparseNames.unwrapElements()
I've seen a few similar questions (like this one) but they don't address how to create the method as an extension.
(this is tagged with Xcode6.1 to denote the version of Swift I'm using)
Note: Swift 1.2 Beta 3 has introduced the flatMap function which helps with optionally chaining arrays. See this excellent blog post here
You can't do this right now in Swift. To add that function as an extension to Array, you'd have to mark somehow that it's only callable with certain kinds of arrays: those with optional values as the subtype. Unfortunately, you can't further specialize a generic type, so global functions are the only way possible.
This is the same reason Array has a sort method that takes a comparison function as a parameter, but it doesn't have a sort that "just works" if the array is full of Comparable members - to get that kind of function, you have to look at the top-level sort:
func sort<T : Comparable>(inout array: [T])
Have you tried using filter and map for that?
let array: [String?] = ["Hello", nil, "World"]
let unwrapped = array.map{$0 ?? nil}.filter{$0 != nil}.map{$0!}
println("unwrapped: \(unwrapped)")
// prints "unwrapped: [Hello, World]"
The first map uses the Nil Coalescing Operator to unwrap if possible. Although, I return nil regardless since the following filter removes all nil values. The last map does the actual unwrapping.
You can do this. Here is how:
extension Array {
func catOptionals<A>() -> [A] where Element == A? {
return self.flatMap{ $0 }
}
}

Resources