I've been trying to swap 2 objects without using a temp value, which be done like so:
var a = "Hello, "
var b = "world!"
(a,b) = (b,a)
a // "world!"
b // "Hello, "
Does anyone know how the language is doing this, is the second tuple (b,a) stored in memory to allow the first one to reassign itself, or does it do it all by switching references?
Thanks in advance
This kind of "switching" does the following:
Replaces the pointers for class types
var classA = NSString(string: "foo")
var classB = NSString(string: "bar")
NSLog("%p %p", classA, classB) // 0x7fecd351def0 0x7fecd341cc30
(classA, classB) = (classB, classA)
NSLog("%p %p", classA, classB) // 0x7fecd341cc30 0x7fecd351def0
Creates new values (copies) for value types
var valueA = "baz"
var valueB = "qux"
NSLog("%p %p", valueA, valueB) // 0x7fecd34201b0 0x7fecd34211e0
(valueA, valueB) = (valueB, valueA)
NSLog("%p %p", valueA, valueB) // 0x7fecd351c880 0x7fecd351de90
Related
I have a simple class in my application:
class MyClass{
var Name: String
var Foo1: Bar
var Foo2: Bar?
//var Foos: [Bar]
}
Foo1 is never nil, and Foo2 is optional, so it might be nil.
Instead of having an init like the one below, I'd like to rather have a list property Foos: [Bar], that might contain 1 or 2 elements.
init(_ Name: String, _ Foo1: Bar, _ Foo2: Bar?){
self.Name = Name
self.Foo1 = Foo1
self.Foo2 = Foo2
}
In C# I'd write something like MyClass m = new MyClass("m", New List<Bar>{Bar1, Bar2}) or MyClass m = new MyClass("m", New List<Bar>{Bar1, null}). I'd prefer to rather have one property in MyClass as a List, instead of two separate fields where one might be nil.
I've tried this initializer:
init(_ Name: String, _ Foos: [Bar]) {
self.Name = Name
self.Foos = Foos
}
But when I try to pass an anonymous List to the initializer, I get this warning:
let m = MyClass("m", [Bar]().append(B1))
Cannot use mutating member on immutable value: function call returns immutable value
How can I pass a populated anonymous list to the initializer in Swift, like I would've done in C#?
Try this code
struct Bar { }
class MyClass {
var name: String
var foos: [Bar?]
init(name: String, foos: [Bar?]) {
self.name = name
self.foos = foos
}
}
let bar0 = Bar()
let bar1: Bar? = nil
let object = MyClass(name: "String", foos: [bar0, bar1])
Hope you got the idea. And read more about how it works in Swift
The most challenging requirement, which is also not met by the accepted answer:
Instead of having an init like the one below, I'd like to rather have a list property Foos: [Bar], that might contain 1 or 2 elements.
One way of dealing with this could be a custom runtime error.
enum BarWrapperError: Error {
case emptyList
}
To pass the list and check if it at least contains one element, you can introduce another type
struct BarWrapper {
init(bars: [Bar]) throws {
guard bars.count > 0 else {
throw BarWrapperError.emptyList
}
self.bars = bars
}
let bars: [Bar]
var firstBar: Bar {
return bars[0]
}
var otherBars:[Bar] {
return Array(bars[1 ..< bars.count])
}
}
BarWrapper is initialised with a list of bars. If this list is empty, it will throw an error.
your MyClass would now look like:
class MyClass {
let name: String
let firstBar: Bar
let otherBars: [Bar]
init(name: String, barWrapper: BarWrapper) {
self.name = name
self.firstBar = barWrapper.firstBar
self.otherBars = barWrapper.otherBars
}
}
If you care for the error and want to continue the execution, you can use this like
do {
let bar0 = Bar()
let bar1 = Bar()
let barWrapper = try BarWrapper(bars: [bar0, bar1])
let object = MyClass(name: "String", barWrapper: barWrapper)
print(object.otherBars)
} catch BarWrapperError.emptyList {
print("empty bar list")
}
If you rather want to crash the app if the list is empty, you can shorten it to
let bar0 = Bar()
let bar1 = Bar()
let barWrapper = try! BarWrapper(bars: [bar0, bar1])
let object = MyClass(name: "String", barWrapper: barWrapper)
print(object.otherBars)
by using try!
You can also do
let bar0 = Bar()
let bar1 = Bar()
if let barWrapper = try? BarWrapper(bars: [bar0, bar1]) {
let object = MyClass(name: "String", barWrapper: barWrapper)
print(object.otherBars)
}
if you don't need error handling and your app would be still operational if the MyClass instance isn't created.
I'm trying to figure out how to create a pointer to a pointer in Swift. Now, I know we don't exactly have pointers in Swift, but here is what I am trying to accomplish:
var foo = objA() //foo is variable referencing an instance of objA
var bar = foo //bar is a second variable referencing the instance above
foo = objA() //foo is now a reference to a new instance of objA, but bar
//is still a reference to the old instance
I would like to have bar be a reference to the foo variable instead of it being a reference to the foo object. That way, if foo becomes a reference to a different object, bar goes along for the ride.
One way of having a secondary reference to a variable would be a computed variable:
class C {}
var a = C()
var b: C { return a } // b is a computed variable, returning the current value of a
b === a // true
a = C()
b === a // true, whereas "var b = a" would have made this false
I believe this is what you want:
class O {
let n: Int
init(n: Int) { self.n = n }
}
var foo = O(n: 1)
var bar = withUnsafePointer(&foo) {$0}
print(bar.pointee.n) // Prints 1
foo = O(n: 2)
print(bar.pointee.n) // Prints 2
(Replace pointee with memory for Swift < 3.0)
I really don't know why you'd want that though.
You can try to use UnsafeMutablePointer. See an example below:
let string = UnsafeMutablePointer<String>.alloc(1)
string.initialize("Hello Swift")
print(string.memory)
let next = string
next.memory = "Bye Bye Swift"
print(string.memory) // prints "Bye Bye Swift"
But it smells a little and It will be better to avoid using technique like this.
Say I have an array of Animals and I'd like to cast it to an array of Cats. Here, Animal is a protocol that Cat adopts. I'd like something like let cats: [Cat] = animals as! [Cat] but this seg faults in compilation (btw I'm on both Linux Swift 3 and Mac Swift 2.2). My workaround is to just create a function that downcasts each item individually and adds it to a new array (see small example below). It produces the desired result, but isn't as clean as I'd like.
My questions are:
is this totally dumb and I'm just missing an easier way to do this?
how can I pass a type as the target parameter in the function below, rather than passing an instance? (e.g. I'd like to pass Cat.self rather than Cat(id:0) but doing so causes an error saying cannot convert Cat.Type to expected argument type Cat)
Here's what I have so far:
protocol Animal: CustomStringConvertible
{
var species: String {get set}
var id: Int {get set}
}
extension Animal
{
var description: String
{
return "\(self.species):\(self.id)"
}
}
class Cat: Animal
{
var species = "felis catus"
var id: Int
init(id: Int)
{
self.id = id
}
}
func convertArray<T, U>(_ array: [T], _ target: U) -> [U]
{
var newArray = [U]()
for element in array
{
guard let newElement = element as? U else
{
print("downcast failed!")
return []
}
newArray.append(newElement)
}
return newArray
}
let animals: [Animal] = [Cat(id:1),Cat(id:2),Cat(id:3)]
print(animals)
print(animals.dynamicType)
// ERROR: cannot convert value of type '[Animal]' to specified type '[Cat]'
// let cats: [Cat] = animals
// ERROR: seg fault
// let cats: [Cat] = animals as! [Cat]
let cats: [Cat] = convertArray(animals, Cat(id:0))
print(cats)
print(cats.dynamicType)
Am I missing an easier way to do this?
You can use map to make the conversion:
let cats: [Cat] = animals.map { $0 as! Cat }
how can I pass a type as the target parameter in the function below, rather than passing an instance?
First, you need to remove the instance parameter:
func convertArray<T, U>(array: [T]) -> [U] {
var newArray = [U]()
for element in array {
guard let newElement = element as? U else {
print("downcast failed!")
return []
}
newArray.append(newElement)
}
return newArray
}
Since you cannot specify type parameters explicitly, you need to provide the compiler with some info to deduce the type of U. In this case, all you need to do is to say that you are assigning the result to an array of Cat:
let cats: [Cat] = convertArray(animals)
As of Swift 4.1 using compactMap would be the preferred way, assuming you don't want the method to completely fail (and actually crash) when you have any other Animal (for example a Dog) in your array.
let animals: [Animal] = [Cat(id:1),Dog(id:2),Cat(id:3)]
let cats: [Cat] = animals.compactMap { $0 as? Cat }
Because compactMap will purge any nil values, you will end up with an array like so:
[Cat(1), Cat(3)]
As a bonus, you will also get some performance improvement as compared to using a for loop with append (since the memory space is not preallocated; with map it automatically is).
Please see following code:
let myDict = [Int:Object]()
func task(newId: Int) {
var newObj = myDict[newId]
if (newObj == nil) { // Question (1)
newObj = Object()
myDict[newId] = newObj
newObj!.doSomething() // Question (2)
}
}
Question (1): I am trying to see if an object associated with newId already exits in myDict. If not, create one and assign it in myDict. I am wondering if any better way to do this? It doesn't look very "swift" right now :)
Question (2): I have to add ! here, but I feel kind of odd that I still have to force unwrapping it even I just created a new object one line above. (no Failable Initializer in Object)
Any advise to help me/correct me to know better about Swift is appreciated. Thanks.
var dict: Dictionary<Int,Int> = [1:1,2:2]
let o = dict[3] ?? Int(3)
// now do something with o, it goes from you dict, or it is the 'new' one
// finaly you can update you dict with 'new' o
dict[3] = o
from apple docs
The nil coalescing operator (a ?? b) unwraps an optional a if it
contains a value, or returns a default value b if a is nil. The
expression a is always of an optional type. The expression b must
match the type that is stored inside a.
I'll though I'd add some notes w.r.t. your code that I find important to point out. After these notes, I'll add two quick answers to your question.
First, lets just analyse your code as it is. We note that you have not told us the type of Object, which means that the behaviour of the code is not well-defined, in the sense that it will behave differently depending on if Object is of value- of reference-type.
For this, we'll look a at a full MWE for your case, and here, we'll construct your Object type as a struct type (value type). Now, consider
// and for this example, assume your object is of value-type struct
struct Object {
var someText = "default"
mutating func doSomething() {
someText += "_didSomething"
}
}
// NOTE 1: if you want task(...) to play around with your dictionary, you
// need to pass your dictionary as an argument. In this case, I've used
// inout (see below).
func task(newId: Int, inout myDict: Dictionary<Int,Object>) {
var newObj = myDict[newId]
if (newObj == nil) {
newObj = Object()
myDict[newId] = newObj // this copies newObj by _value_ to
// your dictionary
newObj!.doSomething() // This will not affect the previous
// _copy_ of newObj in your dictionary
}
}
Now, in the code above, you assign newObj to a new entry in your dictionary, but if Object is of value type, this is a value-copy assignment. This means that the following modifications to newObj are performed on a local instance of Object, living only in the scope of the if statement.
As expected, we see that the .doSomething() call on local newObj after value-assignment to your dictionary does not affect the dictionary entry.
var myDict = [Int:Object]()
task(1, myDict: &myDict)
// _inout_: myDict _copied_ to task(), copy modified in task,
// and modified copy again _copied back_ to caller, myDict.
let isThereAStringInHere = myDict[1]?.someText ?? "nope" // -> "default"
// as expected, we get "default" and not "default_didSomething" here
let whatAboutHere = myDict[2]?.someText ?? "nope" // -> "nope"
// as expected, entry <2:Object> does not exist.
Now, the important part here was:
(If you don't know what type you are dealing with, or just to be extra safe) always assume value-type assignments. If Object was of class type, the assignment myDict[newId] = newObj would have been by reference and the subsequent modification newObj!.doSomething() would have applied to the class instance in the dictionary myDict
Ok, after these notes, let's answer your questions.
Question 1
As has been mentioned in previous answer, as well as used in the discussion above, the nil coalescing operator can be used in cases as this. I'll add that, in this context, an if let clause might work just as well. We modify your task(...) function to be:
func taskNew(newId: Int, inout myDict: Dictionary<Int,Object>) {
if let _ = myDict[newId] {
// possibly do something with existing entry
}
else {
// add new entry
var myNewObj = Object()
myNewObj.doSomething()
myDict[newId] = myNewObj
}
}
taskNew(2, myDict: &myDict)
let whatAboutNow = myDict[2]?.someText ?? "nope" // -> "default_didSomething"
The if let clauses are very "Swifty".
If you want to do something with your dictionary entry both for the use where it exist of where you create txt, you could replace the taskNew function above with this condensed one:
func taskNewShort(newId: Int, inout myDict: Dictionary<Int,Object>) {
myDict[newId] = myDict[newId] ?? Object()
myDict[newId]?.doSomething()
}
taskNewShort(3, myDict: &myDict)
let andNow = myDict[3]?.someText ?? "nope" // -> "default_didSomething"
Question 2
The reason for the force unwrapping within your if clause if that your havenĀ“t performed any explicit optional checking, meanwhile defining the myObj as
var newObj = myDict[newId] // <-- typ: Object? (optional Object)
Since newObj is of type optional, you'll have to unwrap at some point. Also, look at the value assignment to newObj in the if clause
newObj = Object() // assigns Object type to Object? type
// -> newObj is still optional (no down casting)
If you look at my answer to Question 1 above, you'll see that newObj is at no point an optional, and lives only in the clause where we know that a new Object instance will be added (copied) to your dictionary.
The full code for this answer follows, to simplify just copying into a playground for tracking what happens. Playgrounds are great for studying these kinds of behaviours.
struct Object {
var someText = "default"
mutating func doSomething() {
someText += "_didSomething"
}
}
func task(newId: Int, inout myDict: Dictionary<Int,Object>) {
var newObj = myDict[newId]
if (newObj == nil) { // Question (1)
newObj = Object()
myDict[newId] = newObj
newObj!.doSomething() // Question (2)
}
}
var myDict = [Int:Object]()
task(1, myDict: &myDict)
let isThereAStringInHere = myDict[1]?.someText ?? "nope" // -> "default"
let whatAboutHere = myDict[2]?.someText ?? "nope" // -> "nope"
func taskNew(newId: Int, inout myDict: Dictionary<Int,Object>) {
if let _ = myDict[newId] {
// possibly do something with existing entry
}
else {
// add new entry
var myNewObj = Object()
myNewObj.doSomething()
myDict[newId] = myNewObj
}
}
taskNew(2, myDict: &myDict)
let whatAboutNow = myDict[2]?.someText ?? "nope" // -> "default_didSomething"
func taskNewShort(newId: Int, inout myDict: Dictionary<Int,Object>) {
myDict[newId] = myDict[newId] ?? Object()
myDict[newId]?.doSomething()
}
taskNewShort(3, myDict: &myDict)
let andNow = myDict[3]?.someText ?? "nope" // -> "default_didSomething"
I would write like this:
var myDict = [Int:Object]()
func task(newId: Int) {
if myDict[newId] == nil {
let newObj = Object()
myDict[newId] = newObj
newObj.doSomething()
}
}
Edit: inside this block you'll have non-null newObj
if let newObj = myDict[newId] {
newObj.doSomethingElse()
}
I know swift has both reference types and value types. And I know Int is a value type. But how can I store a reference to an integer?
var x:Int = 1
var y:Int = x // I want y to reference x (not copy)
++y
println(x) // prints 1, but I want 2
I tried using boxed types, and I tried using array of Int, but neither works for holding a reference to integer.
I guess I can write my own
class IntRef {
var a:Int = 0
init(value:Int) { a = value }
}
var x:IntRef = IntRef(value: 3)
var y = x
++y.a
println(x.a)
seems a bit awkward.
Unfortunately there is no reference type Integer or something like that in Swift so you have to make a Box-Type yourself.
For example a generic one:
class Reference<T> {
var value: T
init(_ value: T) { self.value = value }
}
You can also use closures. I think these better because they are more powerful and also more specific. They not only store a reference, but they also indicate how the reference will be used. For example,
var x:Int = 1
var setx = { (a:Int) in x = a }
var getx = { x }
setx(getx() + 1)
println(x) // This will print 2
I don't recommend actually defining getx/setx. Define a closure that does a specific task for your application.