Can't assign to constant value Swift - ios

I don't know why I got this error
Cannot assign to value: 'x' is a 'let' constant
with this code :
func swap(x:AnyObject,y:AnyObject){
let tmp = x
x=y
y=tmp
}

Function parameters are constants in Swift. In previous versions you could make them mutable by marking them with var, but this is going away in Swift 3.
If you want to actually swap the passed values, you have to declare them inout:
func swap(inout x: AnyObject, inout y: AnyObject) {
let tmp = x
x = y
y = tmp
}
or just...
func swap(inout x: AnyObject, inout y: AnyObject) {
(x, y) = (y, x)
}

Related

Custom NSCoding object, Swift (map)

I have this class :
class Point: NSCoding {
var x: String?
var y: Double?
override func mapping(map: Map) {
self.x <- map["x"]
self.y <- map["y"]
}
...
In my ViewModel I have a function that generates an array of Double.
I need to create a var with those Double to the y parameters of Points, and 2 string to the x parameters.
I've done something like this but this was with a Point object so everything fits.
let points = PointObject.map { point in
Point(x: point.x ?? "0", y: point.y ?? 0.0).self
}
Any suggestion/help? I'm not very familiar with this
Given two arrays of String/x and Double/y values:
let xValues = ["0", "1"]
let yValues = [2.0, 3.0]
you can create Points using zip and map
let points = zip(xValues, yValues).map {
Point(x: $0.0, y: $0.1)
}

Array map, Swift

I have a custom Rules class.
class Rules: NSCoding {
var x: String?
var y: Double?
override func mapping(map: Map) {
self.x <- map["x"]
self.y <- map["y"]
}
In my viewModel I need to create an object rules and to pass 1 by 1 the elements of two array. The first array is composed by 3 strings, the second array has some Double (more than 3 !!)
This is what I tried so far:
let xValues = ["String1", "String2", "String3"]
let yValues = [1.0, 2.0, 1.5, 2.5, 5.1, 6.0, 8.0]
let rules = zip(xValues, yValues).map {
Rules(x: "\($0.0)", y: $0.1)
}
The problem with this (I guess) is that my rules object has some duplicated string or sometimes more than what I have in my xValues array. (It's possible I am doing something wrong somewhere else ...)
What I need is to pass exactly three strings, and a number of Double which is different, lets say 6 double.
Since zip only returns tuples for those indices where both input arrays have have values, you'll need a method that fills up the smaller array instead, like this:
func zipFill<T, U>(_ arr1: [T], _ arr2: [U]) -> [(T?, U?)] {
let c1 = arr1.count
let c2 = arr2.count
let count = max(c1, c2)
var result = [(T?, U?)]()
for i in 0..<count {
if i < c1 && i < c2 {
result.append((arr1[i], arr2[i]))
} else if i >= c1 {
result.append((nil, arr2[i]))
} else if i >= c2 {
result.append((arr1[i], nil))
}
}
return result
}
let xValues = ["String1", "String2", "String3"]
let yValues = [1.0, 2.0, 1.5, 2.5, 5.1, 6.0, 8.0]
let rules = zipFill(xValues, yValues).map {
Rules(x: $0.0, y: $0.1)
}
print(rules)
// [ {x "String1", y 1}, {x "String2", y 2}, {x "String3", y 1.5},
// {x nil, y 2.5}, {x nil, y 5.1}, {x nil, y 6}, {x nil, y 8} ]
Why don't you just remove duplicates before creating your rules?
Define a generic extension to remove duplicates:
extension RangeReplaceableCollection {
func removingDuplicates<E>(keyPath path: KeyPath<Element, E>) -> Self
where E: Hashable
{
var seen = Set<E>()
seen.reserveCapacity(count)
var new = self
new.removeAll { element -> Bool in
if seen.contains(element[keyPath: path]) {
return true
} else {
seen.insert(element[keyPath: path])
return false
}
}
return new
}
}
Then remove duplicates before zipping:
let xValues = ["String1", "String2", "String3"].removingDuplicates(keyPath: \.self)
let yValues = [1.0, 2.0, 1.5, 2.5, 5.1, 6.0, 8.0].removingDuplicates(keyPath: \.self)
let rules = zip(xValues, yValues).map {
Rules(x: $0.0, y: $0.1)
}
Tidbit: you don't need to use String interpolation for the x argument, because the parameter $0.0 is already a String.

How do you round a UISlider to an int in swift

I was wondering how to round a UISilder value to a int value. Right now it is displaying floats. I am using swift 3 at the moment.
#IBOutlet var slidermove: UISlider!
#IBAction func SliderVal(_ sender: AnyObject) {
print(slidermove)
let x = round(slidermove)
}
round() does not work it will give an error, thanks for anyone that helps
You should round it's value instead of UISlider itself.:
let x = roundf(slider.value) // x is Float
If you need an Int instead of Float, just wrap it with Int initializer:
let x = Int(round(slider.value)) // x is Int
To round a Float to the nearest integer and get the result as
an Int, the (perhaps not so well-known) function lrintf()
can be used. Example:
let x = Float(12.6)
let i = lrintf(x)
print(i) // 13
In your case:
let i = lrintf(slider.value) // `i` is an `Int`

Shift Swift Array

Array of Colors
let colorArray = [
UIColor.redColor(),
UIColor.orangeColor(),
UIColor.yellowColor(),
UIColor.greenColor(),
UIColor.blueColor()
]
The goal is to shift the array:
To start with a different color.
To preserve the circular order of colors.
Example #1
If we wanted to start with the orange color (the color at index 1 in the original array), the array would look like this:
let colorArray = [
UIColor.orangeColor(),
UIColor.yellowColor(),
UIColor.greenColor(),
UIColor.blueColor(),
UIColor.redColor(),
]
Example #2
If we wanted to start with the green color (the color at index 3 in the original array), the array would look like this:
let colorArray = [
UIColor.greenColor(),
UIColor.blueColor(),
UIColor.redColor(),
UIColor.orangeColor(),
UIColor.yellowColor()
]
Short & clear Swift 3 & 4 solution I came up with:
extension Array {
func shifted(by shiftAmount: Int) -> Array<Element> {
// 1
guard self.count > 0, (shiftAmount % self.count) != 0 else { return self }
// 2
let moduloShiftAmount = shiftAmount % self.count
let negativeShift = shiftAmount < 0
let effectiveShiftAmount = negativeShift ? moduloShiftAmount + self.count : moduloShiftAmount
// 3
let shift: (Int) -> Int = { return $0 + effectiveShiftAmount >= self.count ? $0 + effectiveShiftAmount - self.count : $0 + effectiveShiftAmount }
// 4
return self.enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }
}
}
Explanation:
Arrays with no elements and shifts producing the identity of the
original array are returned immediately
To get the effective shift amount regardless of the amount passed with the function, we do some modulo calculation to get rid of shifts that would rotate the elements in the array more than once (e.g. in an Array with 5 Objects, a shift of +7 is the same as a shift of +2). Since we always want to shift to the right, in order to be done with one simple function instead of two, negative inputs have to be dealt with (e.g. in an Array with 5 Objects, a shift of -2 is the same as a shift of +3). Therefore we adjust the negative results of the modulo calculation by the length of the array.
Of course those 3 lines could be done in one, but I wanted to make this as readable as possible.
Now we prepare the actual shift by taking the index ($0) of element and returning the shifted index by adding the amount calculated in step 2. If the new index lands outside of the array length, it needs to be wrapped around to the front.
And finally we apply all the preparation to our array with some trickery: enumerated() gives us an array of tuples [(offset: Int, element: Int)], which is simply the original index of every element and the element itself. We then sort this enumerated array by the manipulated offset (aka the element's index) via applying the function from step 3. Lastly we get rid of the enumeration by mapping the sorted elements back into an array.
This extension works with arrays of any type. Examples:
let colorArray = [
UIColor.red,
UIColor.orange,
UIColor.yellow,
UIColor.green,
UIColor.blue
]
let shiftedColorArray = [
UIColor.green,
UIColor.blue,
UIColor.red,
UIColor.orange,
UIColor.yellow
]
colorArray.shifted(by: 2) == shiftedColorArray // returns true
[1,2,3,4,5,6,7].shifted(by: -23) // returns [3,4,5,6,7,1,2]
I know this might be late. But the easiest way to rotate or shift an array is
func shifter(shiftIndex: Int) {
let strArr: [String] = ["a","b","c","d"]
var newArr = strArr[shiftIndex..<strArr.count]
newArr += strArr[0..<shiftIndex]
println(newArr) }
shifter(2) //[c, d, a, b] you can modify the function to take array as input
You can extend Array to include a method to return an array containing the elements of the original array rotated by one element:
extension Array {
func rotate(shift:Int) -> Array {
var array = Array()
if (self.count > 0) {
array = self
if (shift > 0) {
for i in 1...shift {
array.append(array.removeAtIndex(0))
}
}
else if (shift < 0) {
for i in 1...abs(shift) {
array.insert(array.removeAtIndex(array.count-1),atIndex:0)
}
}
}
return array
}
}
To shifts the elements of an array once
let colorArray:[UIColor] = [
.redColor(),
.orangeColor(),
.yellowColor(),
.greenColor(),
.blueColor()
]
let z = colorArray.rotate(1)
// z is [.orangeColor(), .yellowColor(), .greenColor(), .blueColor(), .redColor()]
and twice
let z = colorArray.rotate(2)
// z is [.yellowColor(), .greenColor(), .blueColor(), .redColor(), .orangeColor()]
A variation of #zizutg's answer, that can shift in both directions (positive and negative)
extension Array {
public func shifted(by index: Int) -> Array {
let adjustedIndex = index %% self.count
return Array(self[adjustedIndex..<self.count] + self[0..<adjustedIndex])
}
}
// True modulo function https://stackoverflow.com/a/41180619/683763
infix operator %%
public func %%(_ dividend: Int, _ divisor: Int) -> Int {
precondition(divisor > 0, "modulus must be positive")
let reminder = dividend % divisor
return reminder >= 0 ? reminder : reminder + divisor
}
You can iterate by handling starting index.
func iterate<T>(array:Array<T>, start:Int, callback:(T) -> ()) {
let count = array.count
for index in start..<(start + count) {
callback(array[index % count])
}
}
If you want to start from index 3
iterate(colors, 3, { (color) -> () in println("color - \(color)")})

Swift calling public class in another file

In Swift programming. I have created a public class called Array3d and is inside Array3d.swift file. My ViewController2.swift create a variable called dog by using the Array3d class and i println(dog). However my console does not show the values of the array of dog but show FYP_Table.Array3D instead.
I have created a 3D Array Called dog and inserted some values into it. Now i want to print it to my debugger output. But does not work.
// Array3d.swift
public class Array3D {
var zs:Int, ys:Int, xs:Int
var matrix: [Float]
init(zs: Int, ys:Int, xs:Int) {
self.zs = zs
self.ys = ys
self.xs = xs
matrix = Array(count:zs*ys*xs, repeatedValue:0)
}
subscript(z:Int, y:Int, x:Int) -> Float {
get {
return matrix[ z * ys * xs + y * xs + x ]
}
set {
matrix[ z * ys * xs + y * xs + x ] = newValue
}
}
//ViewController2.swift
class ViewController2: UITableViewController {
var dog = Array3D(zs: 3, ys: 3, xs: 3)
override func viewDidLoad() {
dog[1,0,0] = 1
dog[0,4,0] = 2
dog[0,0,4] = 3
dog[0,4,4] = 4
for z in 0..<3 {
for y in 0..<3 {
for x in 0..<3 {
println(self.dog)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your class doesn't have a description, so it's just printing out the default representation.
func description() -> String {
return String(format: "Array3D zs:%d ys:%d xs:%d", self.zs, self.ys, self.zs)
}
The proper way to do this is to implement the Printable protocol (see here), which is simply a read-only property named description.
var description : String {
return String(format: "Array3D zs:%d ys:%d xs:%d", zs, ys, zs)
}

Resources