Swift struct with 'Any' not copied correctly into a function - swift

Here's my struct -
struct SettingsItem {
var id: String!
var defaultValue: Any!
init() {
}
}
Then it's being used -
var item2 = SettingsItem()
item2.id = "abcd"
item2.defaultVaule = "1234"
f(item2) // <-- breakpoint shows a good item
When executed, item looks good at the breakpoint shown above. But then inside function f, item is all messed up.
func f(item: SettingsItem) {
println(item) // <-- bad item!
}
It looks like item isn't copied correctly when calling f, but when I tried this on a playground it didn't reproduce.
Any ideas for what causes this?
Update
It seems to be working well when I change type of var defaultValue: Any! to anything else, like Int! or String!.
Also tried using a default constructor (removed my init()), didn't help.
Why does it fail to copy when using Any?

In Xcode 6.4 I get the same behaviour in a playground too.
Probably best not to rely on the built-in string-conversion functionality as that’s really only for debugging purposes. Instead, try giving your type an explicit Printable implementation:
extension SettingsItem: Printable {
var description: String {
// make this string whatever you think the appropriate
// string representation of your value is
return "{id: \(id), defaultValue: \(defaultValue)}"
}
}
If I add this, it now prints out this way inside f.
P.S. I’d suggest thinking about ways you can remove the ! and Any from your struct, they will lead to problems in the longer-term.

Related

swift ui handle property changed in observableObject

so - I have a text field on a screen - the data loads asynchronously - so I've created and ObservableObject with a published field, and successfully bind it to the view:
class Blah : ObservableObject
{
#Published var value : Double? = nil
init()
{
load_variable_async().then {result in self.value = result }
}
}
which works perfectly - the view reflects the value of the variable and everything.
But - I want it to work both ways. Published seems to be a bidirectional wrapper, so I want to add something like this:
init()
{
load_variable_async().then {result in self.value = result }
value.when_changed { new_value in asynchronously_save( variable) }
}
and I can't find any way of doing it. Everything I google for puts a sink or some call to a save in the view - which seems completely wrong to me... if I'm reading it in one place, I want to be writing it in the same place - and if I'm already binding the variable to a textfield for instance, and bindings go both ways, then enough connections have already been made
So what am I doing wrong? How do react to value being set, inside my "model" object without explicitly putting some sort of save or other action into the view?
So I found the solution I wanted - the binding from model -> textfield was always working, but the value from textfield -> model I couldn't get working. The magic seems to be this keyword "willSet"
#Published var value : Double? = nil {
willSet( new_value ) {
print("going to save asynchronously now")
}}
works magically.

Generic method override not working in swift

There is a protocol Printable and a struct Printer from a 3rd Party.
protocol Printable {}
struct Printer {
static func print<T>(object: T) -> String {
return "T"
}
static func print<T: Printable>(object: T) -> String {
return "Printable"
}
}
Now i am making a generic
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
and two structs
struct Obj {}
struct PrintableObj: Printable {}
var obj = Generic(args: Obj())
var printableObj = Generic(args: PrintableObj())
When i call the display functions on both of them.
obj.display()
displays T
printableObj.display()
displays T but i want it to print "Printable"
One solution i can think of is having two different generics
struct Generic<T>
struct PrintableGeneric<T: Printable>
Is there any other solution without changing the Printable protocol and Printer struct.
static func print<T>(object: T) -> String {
if object is Printable {
return "Printable"
} else {
return "T"
}
}
Yes. But the answer is a bit weird. The first part makes a decent amount of sense; the second part is just totally weird. Let's walk through it.
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
The correct overload to choose for print is decided at compile time, not runtime. This is the thing that confuses people the most. They want to treat Swift like JavaScript where everything is dynamic. Swift likes to be static because then it can make sure your types are right and it can do lots of optimizations (and Swift loves to do compiler optimizations). So, compile time, what type is args? Well, it's T. Is T known to be Printable? No it is not. So it uses the non-Printable version.
But when Swift specializes Generic using PrintableObj, doesn't it know at that point that it's Printable? Couldn't the compiler create a different version of display at that point? Yes, if we knew at compile time every caller that would ever exist of this function, and that none of them would ever be extended to be Printable (which could happen in a completely different module). It's hard to solve this without creating lots of weird corner cases (where internal things behave differently than public things for instance), and without forcing Swift to proactively generate every possible version of display that might be required by some future caller. Swift may improve in time, but this is a hard problem I think. (Swift already suffers some performance reductions so that public generics can be specialized without access to the original source code. This would make that problem even more complicated.)
OK, so we get that. T isn't Printable. But what if we had a type that was unambiguously Printable that we knew at compile time and lived inside this function? Would it work then?
func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
Oh so close... but not quite. This almost works. The if-let actually does exactly what you want it to do. p gets assigned. It's Printable. But it still calls the non-Printable function. ?!?!?!?!
This is a place I personally think that Swift is just currently broken and have high hopes it will be fixed. It might even be a bug. The problem is that Printable itself does not conform to Printable. Yeah, I don't get it either, but there you go. So we need to make something that does conform to Printable in order to get the right overload. As usual, type erasers to the rescue.
struct AnyPrintable: Printable {
let value: Printable
}
struct Generic<T> {
var args: T
func display() {
if let p = args as? Printable {
print(Printer.print(AnyPrintable(value: p)))
} else {
print(Printer.print(args))
}
}
}
And this will print the way you wanted. (On the assumption that Printable requires some methods, you'd just add those methods to the AnyPrintable type eraser.)
Of course the right answer is not to use generic overloads this way in Printer. It's just way too confusing and fragile. It looks so nice, but it blows up all the time.
To my mind, the only option you have - is to use if-else with type casting in "print()" function
static func print<T>(object: T) -> String {
if let _ = object as? Printable {
return "Printable"
}
return "T"
}
or non-generic variant
static func print(object: Any) -> String {
if let _ = object as? Printable {
return "Printable"
}
return "T"
}

EXC_BAD_ACCESS using protocol composition

I want to configure an object with multiple presentables; I've created protocols for them; so that I can combine them into a concrete presentable.
protocol Presentable {
}
protocol TextPresentable: Presentable {
var text:String { get }
}
protocol ImagePresentable: Presentable {
var image:String { get }
var images:[String] { get }
}
The concrete struct:
struct ConcretePresentable: TextPresentable, ImagePresentable {
var text:String { return "Text" }
var image:String { return "Image" }
var images:[String] { return ["A", "B"] }
}
The next thing would be to have a presenter, and I would check if the passed in presenter is actually valid:
typealias TextAndImagePresentable = protocol<TextPresentable, ImagePresentable>
struct ConcretePresenter {
func configureWithPresentable(presentable: Presentable) {
guard let textAndImagePresentable = presentable as? TextAndImagePresentable else {
return
}
print(textAndImagePresentable.text)
print(textAndImagePresentable.image)
print(textAndImagePresentable.images)
}
}
To configure:
let concretePresentable = ConcretePresentable()
let concretePresenter = ConcretePresenter()
concretePresenter.configureWithPresentable(concretePresentable)
It goes fine if I run this in a playground, with all of the code in the same place. However, once I put this in a project and split it up into multiple files (ConcretePresenter.swift, ConcretePresentable.swift holding the concrete structs and Presentable.swift which holds the protocols), I get a EXC_BAD_ACCESS.
Why does that happen?
As a disclaimer, I don't necessarily find this answer very satisfying, but it does work.
So, once I noticed that the text & image properties were being returned in each others places (the value for text is being returned by the image property and vice versa), I figured the problem had something to do with what Swift is doing with managing pointers here.
So, out of curiosity, I wanted to add a truly scalar value to the protocols. I added a value property as an Int to the TextPresentable protocol:
protocol Presentable {}
protocol TextPresentable: Presentable {
var text:String { get }
var value: Int { get }
}
protocol ImagePresentable: Presentable {
var image:String { get }
var images:[String] { get }
}
And then I set up the concrete implementation to return some known value. Here, we're returning 0.
struct ConcretePresentable: TextPresentable, ImagePresentable {
var text:String { return "SomeText" }
var value: Int { return 0 }
var image:String { return "SomeImage" }
var images:[String] { return ["A", "B"] }
}
After running this code, we still get the same crash, but I notice that value, which really shouldn't have a problem printing 0 is instead printing some very large number: 4331676336. This isn't right at all.
I also changed images from an array to a dictionary to see if the error persists--it does. It seems the crash is related to collections and not specific to arrays.
From here, I tried some other things.
I tried making ConcretePresentable a class rather than a struct.
class ConcretePresentable: TextPresentable, ImagePresentable
That resulted in the same behavior.
I tried making ConcretePresentable conform to the typealias rather than the protocols independently:
struct ConcretePresentable: TextAndImagePresentable
That resulted in the same behavior.
I tried doing both of the aforementioned at once:
class ConcretePresentable: TextAndImagePresentable
Yet still the same behavior.
I did come up with one way to make it work though. Make a protocol that conforms to the two protocols in your typealias and make ConcretePresentable conform to that:
protocol TextAndImagePresentable: TextPresentable, ImagePresentable {}
struct ConcretePresentable: TextAndImagePresentable {
// ...
}
The problem here is that if you don't explicitly make ConcretePresentable conform to the protocol, it will fail the guard let even if it does conform to TextPresentable and ImagePresentable.
I asked about this on Swift Users and filled a bug.
Confirmed to be a bug in the compiler:
https://bugs.swift.org/browse/SR-4477
Fixed by Joe Groff now:
Joe Groff added a comment - 2 hours ago
Merged. Should be fixed in future snapshots.
struct uses value semantics and so properties are copied. Swift should have reported this as an error since you are trying to inherit from two protocols which derive from the same base protocol. In classes this will work but in struct it wont because of value semantics for struct. In case you decide to add a variable to Presentable protocol Swift would be confused which ones to bring into the struct. From TextPresentable or ImagePresentable
You should use #protocol Presentable : class and then convert ConcretePresentable to class to fix this.
protocol Presentable : class {
}
class ConcretePresenter {...
The problem is in the cast of the Presentable to TextAndImagePresentable. The guard let succeed, but creates an invalid value (I don't know exactly why).
One way to check it, is look to the console on the execution of the commands:
print(textAndImagePresentable.text)
print(textAndImagePresentable.image)
print(textAndImagePresentable.images)
That will print:
Image
Text
Program ended with exit code: 9
One way to avoid it is to change your method signature to avoid the casting:
func configureWithPresentable(presentable: TextAndImagePresentable) {
print(presentable.text)
print(presentable.image)
print(presentable.images)
}
And, in my opinion, since nothing will happen if the presentable do not conform to both protocols, makes more sense to delimiter it on the method signature.

Optional Binding, Capturing References and Closures [possible bug]

I have been trying to get myself acquainted with Swift, but I recently came across this peculiar problem involving Optional Bindings and capturing references within the context of Closures.
Given the following declarations (code abbreviated for clarity; full code provided at the end):
class Thing
{
func giveNameIfSize() -> String? {
/.../
}
}
typealias IterationBlock = (Thing) -> Bool
class Iterable
{
func iterate(block: IterationBlock) {
/.../
}
}
An Iterable object can store a collection of Things and can iterate through them using a closure. Now say we wanted to find the name of the Thing object that has a size property set up. We could do something like this:
var name: String?
iterable.iterate { (someThing) -> Bool in
/*
Assigning the result of the giveNameIfSize() function to
a variable 'name' declared outside of the closure and
captured by reference
*/
if name = someThing.giveNameIfSize() {
return true
}
return false
}
However, the code above generates the following compiler error:
Cannot assign to immutable value of type 'String?'
Curiously enough, the problem disappears when we use another variable in the optional binding:
iterable.iterate { (someThing) -> Bool in
if var tempResult = someThing.giveNameIfSize() {
name = tempResult
return true
}
return false
} /* COMPILES AND RUNS */
The problem is also resolved if we assign a value to the externally declared variable name outside of the optional binding:
iterable.iterate { (someThing) -> Bool in
name = someThing.giveNameIfSize()
if name != nil {
return true
}
return false
} /* ALSO COMPILES AND RUNS */
Full source code here.
Obs.: Tested this code with Swift 1.2, not 2.0.
====
Is this a bug? Or am I missing something?
The error you're receiving is a little misleading, but the underlying problem here is that you're trying to do something that Swift doesn't support. In Swift, you can't use the result of assignment in a condition.
That being said, both of your proposed alternative methods will work, although I tend to think that the first of the two is a little more Swifty.

Xcode6.3.2 Swift bug with static constants

I am trying to figure out why I am having constant compile problems with this type of construct in Xcode 6.3.2.
class Foo {
static let CONSTANT_NAME = "CONSTANT_STRING"
...
func bar () -> String {
var s = String(format:"%s,%d\n", CONSTANT_NAME, 7)
return s
}
...
}
As I understand the language, this should be perfectly legal code however Xcode is constantly (hah-pun) having issues with it raising the error
"there is no member CONSTANT_NAME in class Foo"
If I get lucky and force it to clean, and then rebuild it will some times sort itself out and work. Other times, even doing that, then trying an open/close project will still not resolve the issue.
So, I guess my implicit follow up question (if the answer to the above is - it is legal code) is: is the Xcode Swift compiler that buggy that even basic things like this are likely to cause problems? If so, swift seems to be in a pretty bad state.
static is class property, that means you have to call it like this ClassName.property
class Foo {
static let CONSTANT_NAME = "CONSTANT_STRING"
func bar () -> String {
var s = String(format:"%s,%d\n", Foo.CONSTANT_NAME, 7)
return s
}
}
That is not a bug. That is what it should be. A class property "belongs" to the class.
If you want your code work without using ClassName, do not use static
class Foo {
let CONSTANT_NAME = "CONSTANT_STRING"
func bar () -> String {
var s = String(format:"%s,%d\n",CONSTANT_NAME, 7)
return s
}
}
More details in the Apple Documentation
The static let syntax is legal and valid. The issue is that you must fully qualify that variable when you access it:
var s = String(format:"%s,%d\n", Foo.CONSTANT_NAME, 7)
The compiler error is a bit obtuse, but it is telling the truth... CONSTANT_NAME is not a member, but a type property of class Foo: Swift Type Properties
I hear you about saving key strokes. I've personally been trying to make my Swift code as idiomatic as possible by milking every short cuts but when you find code like this, you should be glad that the compiler asks you to keep on the safe side:
class Foo {
static let CONSTANT = "hello"
func bar() -> String {
let CONSTANT = "bye"
return CONSTANT // I know which one! Thanks Swift!
}
}
println(Foo.CONSTANT)
println(Foo().bar())