Casting Syntax to Loop Through Array of Arrays in Swift - ios

I have an NSArray consisting of NSArrays of strings created in Objective-C.
I now want to loop through the items in the array in a swift class and am having trouble with the syntax.
The original Objective-C Array of arrays looks like the following:
NSArray* shapes =#[#[#"square",#"square.png"],#[#"circle",#"circle.png"],#[#"square",#"square.png"]];
I am able to get and print the Array from the Objective-C class using:
let shapes:Array = Utilities.sharedInstance().getShapes
The following to loop through the array, however, is not compiling:
var term : String = ""
var pic : String = ""
for shape in shapes {
term = shape[1] //ERROR HERE
pic = shape[2] //SAME ERROR HERE
}
It gives the error: Type 'Any' has no subscript members
What is the proper syntax to loop through the elements?

You can try
let shapes = Utilities.sharedInstance().getShapes as! [[String]]
Your Array elements are of type Any so you can't use [] with them until you cast , it's always the case when you use bridged code from objective-c , so you have to be specific about the actual type you use , also i encourage
struct Item {
let term,pic:String
}
Then
let res:[Item] = shapes.map { Item(term:$0[0],pic:$0[1]) }
an irrelevant note but important you can do
NSArray* shapes = #[#"square",#"circle",#"square"];
then the matter of appending .png is simple instead of having an [[String]] directly it's [String]

Related

Unable to compare array value in swift ios

I'm a fresher in iOS
I'm unable to compare in an if statement.
It looks like:
for i in 0.. <array.count
{
if(array[i] == array[i+1])
{
let removedVal = array.remove(i+1)
}
}
The error shows on the if condition:
Binary operator '==' cannot be applied to two 'Any' operands
I googled it, but I am unable to understand what should I do in my case.
=======================================================================
Atlast able to find a solution.
And it worked for me
if ( ((tempArrayForTeamName[i]) as AnyObject).isEqual(tempArrayForTeamName[i+1] as AnyObject) )
need to compare array index position as Any object
And use .isEqual replace of ==
You have to Filter your Array
var newarray = [Int]()
let dictionary = ["A":0,"B":1,"C":1,"D":1,"E":1,"F":1,"G":1,"H":1,"J":0]
let newDictionary = dictionary.reduce([:]) { result, element -> [String: Int] in
guard element.value != 1 else {
return result
}
var newResult = result
newResult[element.key] = element.value
newarray.append(newResult[element.key]!)
return newResult
}
In Swift : Array is a Generic Structure, NSMutableArray is an Objective-C class[will work in Swift].
A NSMutableArray created is of type Any; an array that can contain heterogenous object(could be String, Int or Bool).
An Array is arbitrarily specilized to contain Any (using as [Any])
eg:
var array:Array = ["ABC", 123, true] as [Any]
var nsMutableArray : NSMutableArray = ["ABC", 123, true]
Generic Parameterization:
Even if there is an option to give generic parameterization(Datatype) to your NSMutableArray in Objective C[remember NSMutableArray in an Objective C class],this generic parameterization in unfortunately ignored/not allowed in Swift.
How to specify the datatype:
In Swift one cannot specify the datatype of a NSMutableArray.It would give a compilation error: Cannot specialize non-generic type NSMutableArray.
But one can always specify the datatype of Array(Swift structure) as say: Array<String>.
eg: var array:Array<String> = ["Tom", "Jerry", "Spike"]
Your code has another problem, consider your array has 3 items then i=2, and you are trying to access index 3 (i+1). And program will crash.
Crash point (array[i] == array[i+1])
Please declare specific types array for example
let myArray:[String] = ["a", "b", "c", "d"]

Array to Array copy

I have two arrays. One is:
var array = [[String]]()
The second one is:
var finalArray = NSMutableArray()
array is blank.
I want to copy all the data from the final array to array.
For these two different types of array, direct this code won't work.
array = finalArray
An NSArray can be converted to a Swift array of a given element type with the as? operator, like so:
array = finalArray as? [[String]] ?? []
Note that we have to use the conditional typecast operator as? because it's not known at compile-time whether finalArray actually is an array of string arrays (since NSArray does not use generics in Swift).

"Empty collection literal requires an explicit type" error on Swift3

I have a variable on my class:
var list = []
and I use it on a function of my class:
func chargeData (data: NSArray){
list = data
}
It worked well on my project in Swift 2.3 but when I have updated it to XCode8 and Swift3 it gives to me the following error:
Empty collection literal requires an explicit type
so I have added a typecast to my list variable:
var list = [] as! NSArray
but it gives to me the following alert:
Forced cast of 'NSArray' to same type has no effect
I know that an alert does not broke the application but I would like to solve this error in a proper way.
Did someone got the same error and solved it properly?
Thanks in advance!
This error occurs since implicit conversions are abolished so you have to tell the compiler the explicit type (of the ArrayLiteral []):
var list: NSArray = []
// or
var list = [] as NSArray
The Swift 5 guided tour is pretty explicit about creating empty arrays or dictionaries: https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html#ID461 towards the end of the first section.
To create an empty array or dictionary, use the initializer syntax.
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
Update swift 4 :
var array = [] as [String]
You are mixing ObjectiveC (NSArray) and Swift (Array<T>). Items inside an NSArray are assumed to be NSObject and its subclasses, while Swift has no clue what T is since the array is empty and hence type inference doesn't work.
If you declare it like this:
var data: NSArray = []
there will be a conflict since var means mutable in Swift, but NSArray is immutable in ObjC. You can get around that by changing it to NSMutableArray, which is a subclass of NSArray:
let data = NSMutableArray() // note that we don't need var here
// as NSMutableArray is already mutable
If you want to keep data as Swift's Array, give it a type:
var data = [MyDataModel]()
// or
var data = [AnyObject]()
// usage:
chargeData(data: data as NSArray)

Syntax explanation: square brackets in Swift

I'm studying Swift and got confusing with following syntax:
var treasures: [Treasure] = []
Treasure is custom class, declared as follow:
class Treasure: NSObject { }
In Objective-C square brackets mean method, but what do they mean in Swift?
Ok, this is the meaning of
var treasures: [Treasure] = []
var: you are declaring a variable
treasures: the name of your variable
[Treasure]: the type of your variable, in this case the type is Array of Treasure, the compiler will allow you to insert only object of type Treasure in your Array
[]: the actual object (Array) referenced by your variable, in this case an empty Array.
E.g. if you want the Array to hold 2 elements you can write
var treasures: [Treasure] = [Treasure(), Treasure()]
Hope this helps.
Update:
My example can also be written this way
var treasures = [Treasure(), Treasure()]
Infact thanks to the Type Inference the compiler can deduce the type of the variable treasures looking at the type of the assigned value.
[Treasure] is just a syntax sugar for Array<Treasure>.
The same way [String:Treasure] is just a syntax sugar for Dictionary<String,Treasure>.
[] is just an empty array of the type you defined. The same way [:] is an empty dictionary.
When it comes to Swift and square brackets, the rules are simple. They are used only in two situations:
1) working with Array and Dictionary types:
let vectors : [[Int]] = [[1,2,3],[4,5,6]]
let birthBook : [Int:[String]] = [1987:["John","William"], 1990: ["Mary"]]
2) for subscripting objects that support subscripting:
class RouteMapper {
private var routeMap : [String:String] = [:]
subscript(endpoint: String) -> String {
get {
if let route = routeMap[endpoint] {
return route
}
return "/"
}
set(newValue) {
routeMap[endpoint] = newValue
}
}
}
let routeMapper = RouteMapper()
routeMapper["users"] = "/v1/confirmed/users"
let url = routeMapper["admins"]
Since [ and ] are not allowed in custom operators, these are the only usages for now.

Error trying to access members of Array of AnyObject within a Dictionary - Is there a way around unwrapping?

I have a dictionary set up as:
var jDict = Dictionary<String, AnyObject[]>()
Where the arrays are either a collection of custom buttons (JunkButton) or Labels (JunkLabels).
I am having an issue when trying to access the members of the arrays contained in the Dictionary as follows:
let thisArray = jDict[key]
var aButton = thisArray[0] //Gives error: 'AnyObject[]? does not have a member named 'subscript'
I can get around this by downcasting the whole array as follows:
if let aArray = thisArray as? JunkButton[]{
var aButton = aArray[0]
}
This seems very cumbersome especially if I am sure I know what type the array is made up of beforehand. Is there a way to cast thisArray when it is created that would allow me to extract its elements without unwrapping them each time?
Dictionary always give you Optional value.
Your code is like this
let thisArray : Optional<AnyObject[]> = jDict[key]
You need to unwrap it to get non-optional value
let thisArray = jDict[key]! // thisArray is AnyObject[]
You really shouldn't use a dictionary for this. Swift makes it very easy to use custom little structs or classes instead of dictionaries:
struct JunkItems {
var buttons: [JunkButton] = []
var labels: [JunkLabel] = []
}
Then you can access those items like this without downcasting:
for button in junkItems.buttons {
// ...
}
Or:
if let button = junkItems.buttons[0] {
// ...
}
Btw, the array notation [JunkButton] is new in beta 3.

Resources