Adding objects of a specific type to a generic Array<Any> in Swift? - ios

How do you add an object of a specific type to a generic Array:[Any]? My understanding is that Any should be able to contain any other object. Is this correct? Unfortunately I get an error message when I add specific objects to the generic array.
Example
An array of objects of type "SpecificItemType"
var results:[SpecificItemType] = []
... // adding various objects to this array
The generic target array for these objects
var matchedResults:[Any] = []
matchedResults += results
Error Message
[Any] is not identical to UInt8
What's the problem here? The error message didn't really help.
One more note: Interestingly it is possible to add single objects using append. so the following works
matchedResults.append(results.first)

The compiler cannot resolve the type constraints on
func +=<T, C : CollectionType where T == T>(inout lhs: ContiguousArray<T>, rhs: C)
because you're trying to add [SpecificType] to [Any], hence T != T.
You can fix this by upcasting the most specific array.
var r = results.map { $0 as Any }
matchedResults += r
Concerning the puzzling error, it's due to the overloading on the += operator. The compiler tries to resolve the various versions of the operator, eventually finding this one here:
func +=(inout lhs: UInt8, rhs: UInt8)
Probably it's the last one it tries to resolve, so it throws an error here, telling you that [Any] is different than the expected type for lhs, i.e. UInt8 in this case.

First of all change Any to AnyObject and try following:
matchedResults += (results as [AnyObject])

Related

Constant 'spacesLeft' inferred to have type '()', which may be unexpected Swift

I am building a Tic Tac Toe game with an AI using Xcode 8 and Swift. Here are the relevant variables I am using that are contributing to the error:
var allSpaces: Set<Int> = [1,2,3,4,5,6,7,8,9]
var playerOneMoves = Set<Int>()
var playerTwoMoves = Set<Int>()
var nextMove: Int? = nil
Inside a function defining how the AI will play there are these variables:
var count = 0
let spacesLeft = allSpaces.subtract(PlayerOneMoves.union(playerTwoMoves))
The latter results in the compiler warning:
Constant 'spacesLeft" inferred to have type '()', which may be unexpected
There is an if statement just below that says:
if allSpaces.subtract(playerOneMoves.union(playerTwoMoves)).count > 0 {
nextMove = spacesLeft[spacesLeft.startIndex.advancedBy(Int(arc4random_uniform(UInt32(spacesLeft.count))))]
}
The condition gives the following error:
Value of tuple type '()' has no member 'count'
The statement gives the following error:
Type '()' has no subscript members
I am struggling to find a solution.
subtract modifies Set in place and doesn't return a value, you want to use subtracting
For the first warning, subtract returns Void, so use subtracting:
let spacesLeft = allSpaces.subtracting(playerOneMoves.union(playerTwoMoves))
For the second error, advancedBy is deprecated, you may change like this:
if spacesLeft.count > 0 {
nextMove = spacesLeft[spacesLeft.index(spacesLeft.startIndex, offsetBy: Int(arc4random_uniform(UInt32(spacesLeft.count))))]
}
Set.subtract is a mutating function, so it modifies the Set in place and its return value is Void, which is just a type alias for an empty tuple, (), hence the warning.
You should call Set.substracting, which is the non-mutating version of subtract and returns Set<Set.Element>.
The subtract(_:) function is a mutating function so it will mutate the Set your using to call the function.
From Apple Docs:
subtract(_:)
Removes the elements of the given set from this set.
The reason you're getting the errors is because this function returns Void which in Swift is a typealias for an empty tuple(from Swift's source code). Since Void has no subscripts nor count property/variable you get those errors.
Maybe you should take a look at the subtracting(_:) function, which returns a different Set.
From Apple Docs:
subtracting(_:)
Returns a new set containing the elements of this set that do not occur in the given set.

Swift 3 - No 'sort' candidates produce the expected contextual result type 'NSMutableArray'

I am attempting to sort a mutable array in Swift 3.1.1, but get the same error every time:
No 'sort' candidates produce the expected contextual result type 'NSMutableArray'.
Is there a way to sort a mutable array (Ints only) in ascending order?
In my code, elements from options are being removed. Removed (the array) is adding the removed elements. At the end of the code I am attempting to add the elements from the removed array back to options and sort it.
// set up tiles
var options = NSMutableArray()
var removed = NSMutableArray()
for i in 1...49 {
options.add(i as Int)
print("options\(options.count)")
}
for i in 1...49 {
print("i = \(i)")
options.remove(i)
let tilea: Int = options[Int(arc4random_uniform(UInt32(options.count)))] as! Int
options.remove(tilea)
let tileb: Int = options[Int(arc4random_uniform(UInt32(options.count)))] as! Int
options.remove(tileb)
removed.add([i, tilea, tileb])
print(options.count)
if options.count < 20 {
options.add(removed)
options = options.sort {
$0 < $1
}
}
}
As already mentioned, in Swift you should really be using the Array<T> for this (aka, [T]) instead of NSMutableArray. For instance:
var options = [Int]()
when adding elements to it, use append (and, by the way, you can drop the type cast as well):
options.append(i)
options.append(contentsOf: [i, j, k])
finally, when sorting the array, use the sort function (it doesn't return a value; the array is sorted in-place):
options.sort()
and you don't need even to provide a comparation function since integers conform to the Comparable protocol.
NSMutableArray, among other Objective C types, was implicitly bridged to/from its Swift counterparts. In a move to lessen peoples (usually unnecessary) reliance on these Objective C types, this implicit bridging has been changed in Swift 3, and now needs an explicit type coercion (e.g nsArray as [Int])

Swift Array.indexOf containing nil values

I'm working on an app and I need to know something, because I cannot continue without a solution to my problem. I have an array of the following type:
var samples : [HKSample?]!
Now I want to know if this array contains a specific element and what's the index of that element. When I'm trying to get the index like this
let anotherSample : HKSample = otherSamples.first
let index = samples.indexOf(anotherSample)
I get the following error:
"Cannot convert value of type 'HKSample?' to expected argument type '#noescpae (HKSample?) throws -> Bool'
Please help me!
let anotherSample : HKSample = otherSamples.first
This is incorrect (and shouldn't compile). first will return HKSample? here.
Given that, you're searching for an HKSample? within an [HKSample?]. The problem is that Optional is not Equatable, so you have to use the predicate form of indexOf:
let index = samples.indexOf { $0 == anotherSample }
(where anotherSample is HKSample?, not HKSample.)
It is true that Optional has an == function available when its underlying type is Equatable, but it isn't itself Equatable because you can't currently conform to a protocol with a where clause. In order to make Optional conform, you'd have to be able to write:
extension Optional: Equatable where Wrapped: Equatable {}
But that's not currently supported in Swift. You'll get:
error: extension of type 'Optional' with constraints cannot have an inheritance clause

Assigning generic type to generic with AnyObject type

I can easily do this using Swift's array without any compiler error:
let array: Array<AnyObject> = Array<String>()
But when I try to do the same with my custom type I get compiler error:
class Bar<T> {
}
let bar: Bar<AnyObject> = Bar<String>()
Error is:
Cannot convert value of type 'Bar< String>' to specified type
'Bar< AnyObject>'
How can I achieve the same behaviour with custom type as with native Swift's array?
First of all, note that you cannot "easily" perform your first assignment, seemingly from [Any] to [String]: the reason why this seemingly works is that you are in fact initializing an array of Any elements with an empty array (that happens to be of type [String]). If you try to initialize your Any array with a [String] array that holds actual elements, you'll run into a runtime error:
let anyArr1: Array<Any> = Array<String>() // = [], ok
let anyArr2: Array<Any> = [] // ok
let anyArr3: Array<Any> = [String](count: 2, repeatedValue: "foo")
// = ["foo", "foo"], not ok
/* fatal error: can't unsafeBitCast between types of different sizes */
In so, the comparison in your question don't really make sense. If you want to do type conversion between two array instances of different element types, you need to do this one element at a time, e.g. using .map:
let anyArr4: Array<Any> = [String](count: 2, repeatedValue: "foo").map{ $0 as Any }
print(anyArr4)
// prints "["foo", "foo"]", ok
Since Swift is strongly typed, Bar<Any> and Bar<String> are, inherently, two different types. If you want to initialize one by the other, you'll have to customize your own initializer for this purpose, as simple assignment or casting between these two different types will fail.

Why to use tuples when we can use array to return multiple values in swift

Today I was just going through some basic swift concepts and was working with some examples to understand those concepts. Right now I have completed studying tuples.
I have got one doubt i.e, what is the need of using tuples ? Ya I did some digging on this here is what I got :
We can be able to return multiple values from a function. Ok but we can also do this by returning an array.
Array ok but we can return an multiple values of different types. Ok cool but this can also be done by array of AnyObject like this :
func calculateStatistics (scores:[Int])->[AnyObject]
{
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores
{
if score > max{
max = score
}
else if score < min{
min = score
}
sum += score
}
return [min,max,"Hello"]
}
let statistics = calculateStatistics([25,39,78,66,74,80])
var min = statistics[0]
var max = statistics[1]
var msg = statistics[2] // Contains hello
We can name the objects present in the tuples. Ok but I can use a dictionary of AnyObject.
I am not saying that Why to use tuples when we have got this . But there should be something only tuple can be able to do or its easy to do it only with tuples. Moreover the people who created swift wouldn't have involved tuples in swift if there wasn't a good reason. So there should have been some good reason for them to involve it.
So guys please let me know if there's any specific cases where tuples are the best bet.
Thanks in advance.
Tuples are anonymous structs that can be used in many ways, and one of them is to make returning multiple values from a function much easier.
The advantages of using a tuple instead of an array are:
multiple types can be stored in a tuple, whereas in an array you are restricted to one type only (unless you use [AnyObject])
fixed number of values: you cannot pass less or more parameters than expected, whereas in an array you can put any number of arguments
strongly typed: if parameters of different types are passed in the wrong positions, the compiler will detect that, whereas using an array that won't happen
refactoring: if the number of parameters, or their type, change, the compiler will produce a relevant compilation error, whereas with arrays that will pass unnoticed
named: it's possible to associate a name with each parameter
assignment is easier and more flexible - for example, the return value can be assigned to a tuple:
let tuple = functionReturningTuple()
or all parameters can be automatically extracted and assigned to variables
let (param1, param2, param3) = functionReturningTuple()
and it's possible to ignore some values
let (param1, _, _) = functionReturningTuple()
similarity with function parameters: when a function is called, the parameters you pass are actually a tuple. Example:
// SWIFT 2
func doSomething(number: Int, text: String) {
println("\(number): \(text)")
}
doSomething(1, "one")
// SWIFT 3
func doSomething(number: Int, text: String) {
print("\(number): \(text)")
}
doSomething(number: 1, text: "one")
(Deprecated in Swift 2) The function can also be invoked as:
let params = (1, "one")
doSomething(params)
This list is probably not exhaustive, but I think there's enough to make you favor tuples to arrays for returning multiple values
For example, consider this simple example:
enum MyType {
case A, B, C
}
func foo() -> (MyType, Int, String) {
// ...
return (.B, 42, "bar")
}
let (type, amount, desc) = foo()
Using Array, to get the same result, you have to do this:
func foo() -> [Any] {
// ...
return [MyType.B, 42, "bar"]
}
let result = foo()
let type = result[0] as MyType, amount = result[1] as Int, desc = result[2] as String
Tuple is much simpler and safer, isn't it?
Tuple is a datastructure which is lighter weight than heterogeneous Array. Though they're very similar, in accessing the elements by index, the advantage is tuples can be constructed very easily in Swift. And the intention to introduce/interpolate this(Tuple) data structure is Multiple return types. Returning multiple data from the 'callee' with minimal effort, that's the advantage of having Tuples. Hope this helps!
A tuple is ideally used to return multiple named data from a function for temporary use. If the scope of the tuple is persistent across a program you might want to model that data structure as a class or struct.

Resources