How to have a function accept all types of arrays - ios

I'm kinda new to Swift and I was wondering how do I make a function accept an array that contains all kinds of variables types. I want the function to just accept 'Array' without a specific type but it throws an error. Here's my code:
func length(arry arry: Array)
{
}
I know I have to put a <> after the Array but I need the function to universally accept all arrays.
EDITED:
Whenever I add an extension I get these ridiculous errors. My code is:
//: Playground - noun: a place where people can play
import UIKit
extension Array {
var length: Int {
return self.count
}
}
var arrY = ["Hello", 0]
for(var i = 0; i < length(arry: arrY); i++)
{
print(arrY[i]);
}
arrY.append(28);
var h = arrY.removeAtIndex(0);
print(h);
I get errors saying:
1 On line ten Extensions may not contain stored properties
2 On line eleven Expected Declaration
3 On line eighteen Expected Declaration
Thanks,
Jack

If you want, you can write a generic function:
func length<T>(arry arry: Array<T>)
{
}
In Swift, Apple introduced the concept of Generics which you can also now find it on Xcode 7 and Objective-C. This feature allows you to define the type of each element in the Array or the collection class that you're using. You can define a generic class or a generic method like the sample given. This feature gives you the ability of writing your code in a way that it can work safely with different types, while taking advantage of being type-safe. For example, in the sample that I gave, it's saying that length is a generic method which takes an Array of type T as input. Writing a method like this, allows you to write one method which is capable of accepting arrays of different types. For example, following sample code, is showing that you can use the same method for both array of Int and array of Double:
var arr = [13, 23, 32]
var arr2 = [12.3, 23.5, 13.14, 2.75]
var arr3 = ["foo", "boo"]
length(arr)
length(arr)
length(arr)
For more information on Generics you can check online documents at this Link, and/or watch Swift introduction videos for WWDC 2014, and/or reading generic section of The Swift Programming Language

Using a generic function is the better answer. But you could also use [Any] as a parameter for this function.
func length(array: [Any])->Int{
return array.count
}

If you're used to .length then make an extension to Array with a length property:
extension Array {
var length: Int {
return self.count
}
}
Then you can call it on arrays like you're used to:
["a", "b"].length // 2
[0, 1].length // 2

Related

How to declare a variable to host multiple values [duplicate]

In The Swift Programming Language, it says:
Functions can also take a variable number of arguments, collecting them into an array.
func sumOf(numbers: Int...) -> Int {
...
}
When I call such a function with a comma-separated list of numbers (`sumOf(1, 2, 3, 4), they are made available as an array inside the function.
Question: what if I already have an array of numbers that I want to pass to this function?
let numbers = [1, 2, 3, 4]
sumOf(numbers)
This fails with a compiler error, “Could not find an overload for '__conversion' that accepts the supplied arguments”. Is there a way to turn an existing array into a list of elements that I can pass to a variadic function?
Splatting is not in the language yet, as confirmed by the devs. Workaround for now is to use an overload or wait if you cannot add overloads.
Here's a work around that I found. I know it's not exactly what you want, but it seems to be working.
Step 1: Declare the function you'd like with an array instead of variadic arguments:
func sumOf(numbers: [Int]) -> Int {
var total = 0
for i in numbers {
total += i
}
return total
}
Step 2: Call this from within your variadic function:
func sumOf(numbers: Int...) -> Int {
return sumOf(numbers)
}
Step 3: Call Either Way:
var variadicSum = sumOf(1, 2, 3, 4, 5)
var arraySum = sumOf([1, 2, 3, 4, 5])
It seems strange, but it is working in my tests. Let me know if this causes unforeseen problems for anyone. Swift seems to be able to separate the difference between the two calls with the same function name.
Also, with this method if Apple updates the language as #manojid's answer suggests, you'll only need to update these functions. Otherwise, you'll have to go through and do a lot of renaming.
You can cast the function:
typealias Function = [Int] -> Int
let sumOfArray = unsafeBitCast(sumOf, Function.self)
sumOfArray([1, 2, 3])
You can use a helper function as such:
func sumOf (numbers : [Int]) -> Int { return numbers.reduce(0, combine: +) }
func sumOf (numbers : Int...) -> Int { return sumOf (numbers) }
I did this (Wrapper + Identity Mapping):
func addBarButtonItems(types: REWEBarButtonItemType...) {
addBarButtonItems(types: types.map { $0 })
}
func addBarButtonItems(types: [REWEBarButtonItemType]) {
// actual implementation
}
I know this response does not answer your exact question, but I feel its worth noting. I too was starting to play with Swift and immediately ran into a similar question. Manojlds answer is better for your question, I agree, but again, another workaround I came up with. I do happen to like Logan's better too.
In my case I just wanted to pass an array:
func sumOf(numbers: Array<Int>) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
var someNums = [8,7,2,9,12]
sumOf(someNums)
sumOf([10, 15, 20])
Just wanted to share, in case anyone else was thinking like me. Most of the time I would prefer pass the array like this, but I don't think the "Swiftly" yet. :)
Swift 5
This is an approach with #dynamicCallable feature that allows to avoid overloading or unsafeBitCast but you should make a specific struct to call:
#dynamicCallable
struct SumOf {
func dynamicallyCall(withArguments args: [Int]) -> Int {
return args.reduce(0, +)
}
}
let sum = SumOf()
// Use a dynamic method call.
sum(1, 2, 3) // 6
// Call the underlying method directly.
sum.dynamicallyCall(withArguments: [1, 2, 3]) // 6

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])

Declare an array of Int in Realm Swift

How can I declare an array of integers inside RLMObject?
Like :
dynamic var key:[Int]?
Gives the following error :
Terminating app due to uncaught exception 'RLMException', reason: ''NSArray' is not supported as an RLMObject property. All properties must be primitives, NSString, NSDate, NSData, RLMArray, or subclasses of RLMObject. See https://realm.io/docs/objc/latest/api/Classes/RLMObject.html for more information.'
Lists of primitives are not supported yet unfortunately. There is issue #1120 to track adding support for that. You'll find there some ideas how you can workaround that currently.
The easiest workaround is create a object to hold int values. Then the model to have a List of the object.
class Foo: Object {
let integerList = List<IntObject>() // Workaround
}
class IntObject: Object {
dynamic var value = 0
}
Fortunately arrays of primitive types are now supported in Realm 3.0 and above. (Oct 31 2017)
You can now store primitive types or their nullable counterparts (more specifically: booleans, integer and floating-point number types, strings, dates, and data) directly within RLMArrays or Lists. If you want to define a list of such primitive values you no longer need to define cumbersome single-field wrapper objects. Instead, you can just store the primitive values themselves!
class MyObject : Object {
#objc dynamic var myString: String = ""
let myIntArray = List<Int>()
}
Source: https://realm.io/blog/realm-cocoa-reaches-3-0/
The accepted offer is very costly in term of memory.
You might get a List of very big "n" of objects.
It's not a matter of right and wrong but I think it's good to write here a different workaround.
Another approach:
I decided to use a single string to represent an Int array.
In my Realm class I defined a variable:
dynamic var arrInt: String? = nil
And use it very easily:
let arrToSave = [0, 1, 33, 12232, 394]
<MY_CUSTOM_REALM_CLASS>.arrInt = arrToSave.map { String(describing: $0) }.joined(separator: ",")
And the way back:
let strFetched = <MY_CUSTOM_REALM_CLASS>.arrInt
let intArray = strFetched.components(separatedBy: ",").flatMap { Int($0) }
Will be happy to hear your feedback, as I think this approach is better.
As the error message states, you have to use RLMArray - or rather it's swift equivalent List.
See: Realm docs

How would I properly format this Swift function to map an array?

I'm trying to build a function with swift that will map an array, divide each value in the array by 3, then spit out a new array. This is what I have so far:
func divideby3Map<T, U>(y: [T], z: T -> U) -> [U] {
let array = [int]()
let divideby3Array = array.map { [y] / 3 }
return dividedby3Array
}
divideby3Map([1,2,3,4,5])
Where T and U are the original array, and the new array being returned respectively, and it's done using generics.
I'm sure this isn't written properly, I'm stuck in terms of the right syntax. For example, since the array being returned is represented by the generic [U], I assume I have to use it somewhere in the array being returned, not sure where though.
When writing a generic function, it’s sometimes easier to approach it in 3 steps: first write the code stand-alone using a specific type. Then write the code as a function, still with a specific type. Finally, change the function to be generic.
The first part, dividing an array by 3, can be done like this:
let a = [1,2,3,4,5]
// map is run on the array of integers, and returns a new
// array with the operation performed on each element in a:
let b = a.map { $0 / 3 }
// so b will be [0,0,1,1,1]
// (don’t forget, integer division truncates)
Note the closure you provide between the { } is an operation that will be applied to each element of the array. $0 represents the element, and you divide it by 3. You could also write it as a.map { i in i / 3 }.
To put this into its own function:
func divideby3Map(source: [Int]) -> [Int] {
return source.map { $0 / 3 }
}
No need to declare a fresh array – map will create one for you. You can then return that directly (you can assign it to a temporary if you prefer, but that isn’t really necessary).
Finally, if you want to make it generic, start by adding a placeholder:
func divideby3Map<T>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
Note, there’s only a need for one placeholder, T, because you are returning the exact same type you are passed in.
Except… this won’t compile, because the compiler doesn’t know that T is guaranteed to provide two critical things: the ability to divide (a / operator), and the ability to create new T from integer literals (i.e. to create a T with value 3 to divide by). Otherwise, what if we passed an array of strings or an array of arrays in?
To do this, we need to “constrain” T so our function will only accept as arguments types that provide these features. One such protocol we can use to constrain T is IntegerType, which does guarantee these features (as well as some other ones like +, * etc):
func divideby3Map<T: IntegerType>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
divideby3Map(a) // returns [0,0,1,1,1]
let smallInts: [UInt8] = [3,6,9]
divideby3Map(smallInts) // returns [1,2,3]

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