I want to see how swift String struct pointer changes when I append new string to original one, comparing to Objective C. For Objective C I use this code:
NSMutableString *st1 = [[NSMutableString alloc] initWithString:#"123"];
[st1 appendString:#"456"];
In Objective C st1 string object changes internaly (adds 456 and becomes 123456), but st1 pointer lefts the same and points to the same object. In Swift, since String is not mutable, var st1 must change its address after addition, because it will hold another string, with my strings summ (123456). Is this all correct?
This is my playground code for swift tests:
import Cocoa
var str = "123"
withUnsafePointer(to: &str) { print($0) }
str += "456"
withUnsafePointer(to: &str) { print($0) }
var str2 = "123"
print(Unmanaged<AnyObject>.passUnretained(str2 as AnyObject).toOpaque())
str2 += "456"
print(Unmanaged<AnyObject>.passUnretained(str2 as AnyObject).toOpaque())
and this is results:
0x000000010e228c40 // this are same
0x000000010e228c40
0x00007fb26ed5a790 // this are not
0x00007fb26ed3f6d0
// and they completly different from first two
Why I get same pointer when I use withUnsafePointer? Why I get different pointers when I use Unmanaged.passUnretained? And why pointers received from this methods are completly different?
To better explain the behaviour you're seeing, we can actually look at the String source code.
Here's the full definition of String
public struct String {
/// Creates an empty string.
public init() {
_core = _StringCore()
}
public // #testable
init(_ _core: _StringCore) {
self._core = _core
}
public // #testable
var _core: _StringCore
}
So String is just a wrapper around some type called _StringCore. We can find its definition here. Here are the relevant parts:
public struct _StringCore {
//...
public var _baseAddress: UnsafeMutableRawPointer?
var _countAndFlags: UInt
//...
}
As you can see, the _StringCore doesn't directly contain the buffer of memory that stores the string's content. Instead, it references it externally, via a UnsafeMutableRawPointer.
The first time you declare str, it was given some memory on the stack, at address 0x000000010e228c40. When you made a change to str, you actually had no effect on this String struct's location. Instead, you caused the _baseAddress of the String's _core to change. Array works a very similar way. This is how the string's copy-on-write behaviour is implemented, too.
As for the Unmanaged behaviour, str2 as AnyObject creates a copy of str2, so you end up making 2 different copies, hence the difference in
the printed addressed.
Related
I want to initialize every time a struct with dictionaries. Later, I'm going to use its properties instead a dictionary's keys and values - it seems rather easier. However, when I try the code below, it tells me that "Return from initializer without initializing all stored properties" and "1. 'self.one' not initialized" and "2. 'self.two' not initialized". My question is how to initialize a struct from a dictionary, so that I have basically a struct with the contents of the dictionary? Or how to transform it into struct?
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
for i in three {
self.one = i.key
self.two = i.value
}
} ERROR! - Return from initializer without initializing all stored properties
}
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
one = ""
two = []
for i in three {
self.one = i.key
self.two = i.value
}
} ERROR! - Return from initializer without initializing all stored properties
}
for in clause may have zero runs, in which case struct properties will not be initialized. You have to provide default values (or emit fatalError if you really need to).
While I think your example is pure synthetical, there is no need to loop through array, you can set properties to its last entry.
The issues is that if three is an empty Dictionary, the instance properties one and two don't get initialised. Also, you are overwriting the properties in each iteration of the for loop and the compiler cannot guarantee that there will be any iterations of the loop in compile-time, hence the compiler error.
You could make the initialiser failable to account for this by checking that the dictionary actually contains at least one key-value pair and assigning that first key-value pair to your properties.
struct Blabla {
var one: String
var two: [Int]
init?(three: [String: [Int]]) {
guard let key = three.keys.first, let value = three[key] else { return nil }
one = key
two = value
}
}
However, you should rethink what it is that you are actually trying to achieve, since with your current setup you have a mismatch between your init input values and the properties of your struct.
This code should compile, but it feels unsafe to me to initialize a Struct in this way because:
It assume your dictionary has values in it.
Your stored properties will always have the last value you looped through.
In order to pull values out to satisfy the compiler you need to force unwrap them. (With Dávid Pásztor's guard-letting approach, this can be avoided)
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
self.one = three.keys.first!
self.two = three[three.keys.first!]!
}
}
let input = ["pizza": [1,2]]
let l = Blabla(three: input)
If I were you I would let the memberwise initializer that you get for free do its thing and provide either a specialized initializer to handle your case of taking a Dictionary as input or move that parsing to another function/class/etc....
The compiler error is clear: If the dictionary is empty the struct members are never initialized. But the code makes no sense anyway as each iteration of the dictionary overwrites the values.
Maybe you mean to map the dictionary to an array of the struct
struct Blabla {
let one: String
let two: [Int]
}
let three = ["A":[1,2], "B":[3,4]]
let blabla = three.map{Blabla(one: $0.key, two: $0.value)}
print(blabla) // [Blabla(one: "A", two: [1, 2]), Blabla(one: "B", two: [3, 4])]
struct blabla{
var a : string
var b : [int] = []
init(_ data: [string:[int]]){
// whatever you want to do
}
}
Consider the following code:
struct Card {
var name0: String
var name1: String
}
var cards = [Card]()
cards.append(Card(name0: "hello", name1: "world"))
// Need to perform array index access,
// every time I want to mutate a struct property :(
cards[0].name0 = "good"
cards[0].name1 = "bye"
// ...
// ...
// "good bye"
print(cards[0].name0 + " " + cards[0].name1)
Instead of having to perform multiple array index accessing every time I want to mutate a property in struct, is there a technique to avoid such repeating array index accessing operation?
// Ok. This is an invalid Swift statement.
var referenceToCardStruct = &(cards[0])
referenceToCardStruct.name0 = "good"
referenceToCardStruct.name1 = "bye"
// ...
// ...
There are a lot of good answers here, and you should not think of value types as "a limitation." The behavior of value types is very intentional and is an important feature. Generally, I'd recommend inout for this problem, like matt suggests.
But it is also certainly possible to get the syntax you're describing. You just need a computed variable (which can be a local variable).
let index = 0 // Just to show it can be externally configurable
var referenceToCardStruct: Card {
get { cards[index] }
set { cards[index] = newValue }
}
referenceToCardStruct.name0 = "good"
referenceToCardStruct.name1 = "bye"
print(cards[0].name0 + " " + cards[0].name1)
struct Card {
var name0: String
var name1: String
}
var cards = [Card]()
// every time I want to mutate a struct property :(
cards[0].name0 = "good"
cards[0].name1 = "bye"
Instead of having to perform multiple array index accessing every time I want to mutate a property in struct, is there a technique to avoid such repeating array index accessing operation?
No. When you have an array of struct, then in order to make a change to a struct within the array, you must refer to that struct by index.
If you don't want to see the repeated use of the index, you can hide it in a function using inout:
func mutate(card: inout Card) {
card.name0 = "good"
card.name1 = "bye"
}
for index in cards.indices {
mutate(card:&cards[index])
}
Some day, Swift may include for inout which will allow you to cycle through an array of struct and mutate each struct instance directly. But that day is not yet here.
In answer to the implied question whether it is worth switching to a class just to avoid this repeated use of the index, my answer would be No. There is a good reason for using structs — they are much easier to reason about than classes, and are one of Swift's best features — and I would keep using them if that reason matters to you.
struct is a value type you can't get a reference to it's object with assignment , you should go that way , use a mutating method like https://stackoverflow.com/a/52497495/5820010 or use a class instead
If you don't want to repeat the index, then create a variable from the value you want.
var cards = [Card]()
cards.append(Card(name0: "hello", name1: "world"))
var card = cards[0]
card.name0 = "good"
card.name1 = "bye"
// ...
// ...
cards[0] = card // update the array with the updated card
// "good bye"
print(card.name0 + " " + card.name1)
I think the mutating method is the way to go, as Sh_Khan points out.
In your case, I would do something like:
1> struct Card {
2. var name0: String
3. var name1: String
4. }
5.
6. var cards = [Card]()
7. cards.append(Card(name0: "hello", name1: "world"))
cards: [Card] = 1 value {
[0] = {
name0 = "hello"
name1 = "world"
}
}
8> extension Card {
9. mutating func setNames(name0: String, name1: String) {
10. self.name0 = name0
11. self.name1 = name1
12. }
13. }
14> cards[0].setNames(name0: "x", name1: "y")
15> cards
$R0: [Card] = 1 value {
[0] = {
name0 = "x"
name1 = "y"
}
}
Another approach is a wholesale update of cards[0].
Kind of makes you wish for record updating syntax (a la Haskell or Elm) or dictionary merging-type functionality. But look on the bright side. Maybe Swift's lack of making this easy is testament to the fact that it has static-typing-and-value-semantics-while-allowing-mutation and that combination of features, I think, makes the mutating func or full array element update all but required. I'm not sure Swift has a syntactic feature for updating multiple properties in one shot (without writing your own function or method).
So I'm a little confused because of conflicting information, just looking for some clarity regarding memory allocation for Class properties.
So here are my assumptions, please let me know if any of them are wrong:
In Swift, except for Classes and Functions, everything is passed by Value.
Classes instances (objects) are allocated on the Heap
When you pass an object around, you are passing the pointer
When you reference a property on an object, the pointer is dereferenced, and the value of the property is retrieved
So here's my confusion, say my class has a String property, and an Int property. Both Swift data types, that get passed by value in any ordinary situation.
If I ask for let test = object.stringProperty, am I going to get a copy of my string value copied into my test variable?
Similarly, if I had a method inside of my class,
func getAllProperties() -> (String, Int) {
return (self.stringProperty, self.intProperty)
}
is object.getAllProperties() going to return a copy of the properties in a tuple?
I know it seems like a basic question, but after reading several sources I just ended up more uncertain than when I started
Yes and yes. It doesn't matter that the String and the Int were in a class. You asked for the String or the Int (or both), those are value types, you got copies.
It's easy to prove this to yourself, especially with the String. Just change something about it, and then look back at what the class instance is holding: it will be unchanged.
class C {
var stringProperty : String
init(string:String) {
self.stringProperty = string
}
}
let c = C(string:"hello")
var s = c.stringProperty
s.removeLast()
print(s) // hell
print(c.stringProperty) // hello
If you want to see the class-as-reference in action, make two of the same instance and do something to one of those:
class C {
var stringProperty : String
init(string:String) {
self.stringProperty = string
}
}
let c = C(string:"hello")
let d = c
c.stringProperty = "goodbye"
print(d.stringProperty) // goodbye
I'm working with a C API from Swift and for one of the methods that I need to call I need to give a
UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
More Info:
Swift Interface:
public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t
Original C:
presage_error_code_t presage_predict(presage_t prsg, char*** result);
Generally, if a function takes a UnsafePointer<T> parameter
then you can pass a variable of type T as in "inout" parameter with &. In your case, T is
UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
which is the Swift mapping of char **. So you can call the C function
as
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
From the documentation and sample code of the Presage library I
understand that this allocates an array of strings and assigns the
address of this array to the variable pointed to by prediction.
To avoid a memory leak, these strings have to be released eventually
with
presage_free_string_array(prediction)
To demonstrate that this actually works, I have taken the first
part of the demo code at presage_c_demo.c and translated it
to Swift:
// Duplicate the C strings to avoid premature deallocation:
let past = strdup("did you not sa")
let future = strdup("")
func get_past_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(past)
}
func get_future_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(future)
}
var prsg = presage_t()
presage_new(get_past_stream, nil, get_future_stream, nil, &prsg)
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK {
for var i = 0; prediction[i] != nil; i++ {
// Convert C string to Swift `String`:
let pred = String.fromCString(prediction[i])!
print ("prediction[\(i)]: \(pred)")
}
presage_free_string_array(prediction)
}
free(past)
free(future)
This actually worked and produced the output
prediction[0]: say
prediction[1]: said
prediction[2]: savages
prediction[3]: saw
prediction[4]: sat
prediction[5]: same
There may be a better way but this runs in playground and defines a value r with the type you want:
func ptrFromAddress<T>(p:UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
{
return p
}
var myInt:Int8 = 0
var p = ptrFromAddress(&myInt)
var q = ptrFromAddress(&p)
var r = ptrFromAddress(&q)
What's the point of defining ptrFromAddress, which seems like it does nothing? My thinking is that the section of the Swift interop book which discusses mutable pointers shows many ways to initialize them by passing some expression as an argument (like &x), but does not seem to show corresponding ways where you simply call UnsafeMutablePointer's initializer. So let's define a no-op function just to use those special initialization methods based on argument-passing
Update:
While I believe the method above is correct, it was pointed out by #alisoftware in another forum that this seems to be a safer and more idiomatic way to do the same thing:
var myInt: Int8 = 0
withUnsafeMutablePointer(&myInt) { (var p) in
withUnsafeMutablePointer(&p) { (var pp) in
withUnsafeMutablePointer(&pp) { (var ppp) in
// Do stuff with ppp which is a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
}
}
}
It's more idiomatic because you're using the function withUnsafeMutablePointer which is supplied by the Swift standard library, rather than defining your own helper. It's safer because you are guaranteed that the UnsafeMutablePointer is only alive during the extent of the call to the closure (so long as the closure itself does not store the pointer).
My class has a property that, in other languages, would be a simple Array of Strings, which would be initialized at an object's instantiation. In Swift, I have come up with the following:
class Foo {
var myArray: (String!)[]!
init(arraySize: Int, sourceOfData: SomeOtherClass){
myArray = Array<(String!)>(count: arraySize, repeatedValue:nil)
/* ... code to set the elements of the array using sourceOfData ... */
}
}
This is the only way I have been able to compile my code that allows pre-allocation of the Array's elements. However, I think all those exclamation marks make my code hard to read.
I know I can change my repeatedValue to an arbitrary non-nil string, and simplify the type to String[]!, but that would be a hack.
Also, I can do:
class Foo {
let myArray: String[] = []
init(sourceOfData: SomeOtherClass){
/*loop over sourceOfData*/{
myArray.append(/* computed String value */)
}
}
}
However, this has clearly worse performance, as the compiler cannot guess the length of my Array and allocate a contiguous block of memory for it. Normally, I would not care too much about optimizing the performance of this part of my code, but for this class it is critical.
Is there any way to have legible types without compromising performance?
You don't need to mark myArray as optional as long as you populate it in your init(). And if you can loop over sourceOfData using map something like this would work:
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray = sourceOfData.map {
return $0.computeStringValue()
}
}
}
if you really do need to use a loop, and you can at least determine how large an array you need, you can do something like this:
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray = Array<String>(count: SomeOtherClass.count, repeatedValue: "")
for i, item in enumerate(sourceOfData) {
myArray[i] = item.computeStringValue()
}
}
}
One last note about performance: LLVM is a very sophisticated compiler. You say that it is "obviously worse performance", but this is the kind of code for which static analysis may actually be able to determine the appropriate size of the array. I suggest profiling it with real data for your use case.
You can use the reserveCapacity method on Array. This will make sure there is enough pre-allocated memory to hold your data.
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray.reserveCapacity(sourceOfData.count)
// loop over data calling .append()
}
}