Swift scope of ignored return value? - swift

I have a function similar to the following
class Bar {
deinit {
print("Do some cleanup")
}
}
func foo() -> Bar {
return Bar()
}
The scope of Bar is clear when calling it like this:
func useFoo() {
let bar = foo()
runFunctionA()
// bar goes out of scope: "Do some cleanup" is printed
}
However, what happens when the return value is ignored, will it go immediately out of scope?
func useFoo() {
let _ = foo()
// "Do some cleanup" is printed here?
runFunctionA()
// "Do some cleanup" is printed here?
}
Also, does it make a difference if let _ = foo() is used or only _ = foo()?

In second case, there is no one taking the ownership of returned object and hence ARC releases the object immediately. So, you must see Do some cleanup, before runFunctionA() call.
Also, let _ = foo() is similar to _ = foo
Now, you must be thinking what crap I am writing when you must be looking at different results in your playground.
The thing is, playgrounds are not meant for checking memory related code. Refer this.
If you don't trust me, just check your code in an actual project. I sure did.
Bar:
class Bar {
deinit {
print("Do some cleanup")
}
class func foo() -> Bar {
return Bar()
}
}
ViewController:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
useFoo()
useFooAgain()
}
func useFoo() {
let bar = Bar.foo()
print("inside useFoo")
}
func useFooAgain() {
let _ = Bar.foo()
print("inside useFooAgain")
}
}
Output:
inside useFoo
Do some cleanup
Do some cleanup
inside useFooAgain

Related

Closure var not capture string

This code is not working, how do I repair it?
I try to handle the string and return it, but no result. printing does not output anything to the console
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let x = "hello"
let viewm = viewmodel()
viewm.handler(x)
viewm.handler = { item in
print(item)
}
viewm.execute { (tt) in
print(tt)
}
}
class viewmodel {
var handler:(String) -> Void = {
(data: String) in
}
func execute(complete: #escaping (String) -> Void) {
self.handler = complete
}
}
It is not clear what you are trying to achieve here, but if your issue is that print(item) is not printing anything, that is happening because this code by itself is not going to print anything:
viewm.handler = { item in
print(item)
}
handler property is a closure that receives a String parameter and returns Void. On your viewDidLoad method, you are assigning a closure that complies with those characteristics and, in addition to that, is going to print the passed parameter.
Given that closures are self-contained blocks of functionality, you need to call it in order to execute its block of functionality; but you need to call it after it has been defined; otherwise, it is not going to print anything.
If you write your code in this order, "hello" is going to be printed.
viewm.handler = { item in
print(item)
}
viewm.handler(x)

Swift Quick framework memory leak

I'm using Quick to test my Swift code.
However, I think it doesn't release objects defined in describe scope:
class MyClass {
deinit {
print(self, #function)
}
}
final class MyClassSpec: QuickSpec {
override func spec() {
describe("") {
let foo = MyClass()
it("") {
print(foo)
expect(true).to(beTrue())
}
}
}
}
I don't see any output from print inside deinit, and a debug breakpoint inside the deinit does not get catched.
If I move foo inside it, the deinit is called.
Is this a bug in Quick, or is it normal for deinit not to be called in a test suite?
Apparently the code I wrote was not only retaining the object but was also an anti-pattern.
Even a plain old XCTestCase retains an object:
class MyClass {
deinit {
print(self, #function)
}
}
final class MyClassTest: XCTestCase {
let foo = MyClass()
func testMyClass() {
print(foo)
XCTAssert(true)
}
}
deinit is not called for foo.
This is due to a nature of XCTestCase—it never really gets deinited.
So one should always use setUp & tearDown to manage everything (or more accurately, objects with reference semantics).
I believe this directly translates to QuickSpec as well, so I should always use beforeEach & afterEach in order to manage the objects.
To "fix" the problem, I should test like:
final class MyClassSpec: QuickSpec {
override func spec() {
describe("") {
let foo: MyClass!
beforeEach { foo = MyClass() }
afterEach { foo = nil }
it("") {
print(foo)
expect(true).to(beTrue())
}
}
}
}

Understanding "Use of undeclared type" in inherited generic class

I just came across this curious cookie and can't figure out if I'm more surprised by the fact that this doesn't work as expected or that this the first time I'm seeing this in the past five years using Swift every day.
Now, I expected Bar type to be accessible from Baz, but it isn't:
class Foo<Bar> {
func bar() -> Bar? { nil }
}
class Baz: Foo<String> {
override func bar() -> Bar? { nil } // 💥 Use of undeclared type 'Bar'…
}
It's easily solved with typealias:
class Foo<Bar> {
typealias Bar = Bar // This just feels so wrong…
func bar() -> Bar? { nil }
}
class Baz: Foo<String> {
override func bar() -> Bar? { nil } // 👌 That's it…
}
My questions is: is this mentioned or explained anywhere in the official docs? What's the benefit of hiding Bar from inheriting classes?
One of the reasons this is a rare case is probably because we often pass down the generic type:
class Foo<Bar> {
func bar() -> Bar? { nil }
}
class Baz<Bar>: Foo<Bar> {
override func bar() -> Bar? { nil } // 👌 No problems…
}
And use protocols with associatedtype, which does the same job as typealias above:
protocol P {
associatedtype Bar
}
class Foo<Bar>: P {
func bar() -> Bar? { nil }
}
class Baz: Foo<String> {
override func bar() -> Bar? { nil } // 👌 All good…
}
P.S. I'm not asking how to fix this. I want to know if the current behaviour is mentioned anywhere in the official documentation or, otherwise, if there's a credible article explaining the reasons why this works the way it does.
Foo<Bar> Bar is just a typealias of your 'generic' type (I mean what type you want Int, Double etc.). So if you give String to Foo like (Foo<String>) now Bar alias of the String. And the Bar alias only recognizes from Foo.
class Foo<Bar> {
func bar() -> Bar? { return nil }
}
Incorrect
class Baz: Foo<String> {
override func bar() -> Bar? { return nil } // `Bar` is `String` now so you should use `String?` in your return type
}
Correct
class Baz: Foo<String> {
override func bar() -> String? { return nil }
}
BONUS
hackingwithswift article about Swift Generics

Nested function overloading in Swift

Overloading methods in Swift works as expected, but when I try to overload nested functions, such as
func foo() {
func bar(param: Int) {
// do stuff
}
func bar(param: Double) {
// do stuff
}
// call functions here
}
I get an error saying Definition conflicts with previous value. Why does this happen?
IMHO this is clearer if you consider this variation:
func foo() {
let bar: (param: Int) -> () = { p in
// do stuff
}
func bar(param: Double) {
// do stuff
}
// call functions here
}
With your first bar function definition you are just declaring a constant of type (param: Int) -> ().
Thus with your second declaration you are declaring another constant of different type (param: Double) -> () but having the same name as the already declared bar.
In short it's just like you wrote:
let bar: Int = 0
let bar: Double = 0.0
In which case compiler will complain as well.
Hope this helps.
Good question.
Note that this behaviour/restriction is not documented and the answer is my best guess.
Consider this following piece of code:
func foo() -> (param:Int)->() {
func bar(param: Int) {
// do stuff
}
return bar
}
The function will return the closure bar. If you were to have another closure named bar within the same function, like this...
func foo() -> (param:Int)->() {
func bar(param: Int) {
// do stuff
}
func bar(param: Float) {
// do stuff
}
return bar
}
...they would have conflicting names and the compiler doesn't know what to return. This is same as the following piece of code which you would readily agree to be wrong:
func foo() -> Int {
let a:Int = 0
let a:Int = 0 //Error
return a
}
More observation
The behaviour of a similar set of functions inside a class is weird.
class Test {
func foo(param:Float) {
let bar = { (param:Int) -> () in
//do stuff
}
}
func foo(param:Int) {
let bar = { (param:Int) -> () in
//do stuff
}
}
func anotherFoo() {
println(self.foo) //Compile time error - Ambiguous use of foo
}
}
All though...
class Test {
func foo(param:Float) {
let bar = { (param:Int) -> () in
//do stuff
}
}
func anotherFoo() {
println(self.foo) //Compiles
}
}
Interesting.

Is this ok to do in a swift subclass copy()?

class SubClassType:SuperClassType {
override func copy() -> SubClassType {
return super.copy() as SubClassType
}
}
Note that the super copy is implemented and the SubClassType doesn't add any properties to the super class type, only modifies it's functionality. Really asking because as I was adding support for NSCopying for a behavior tree I typed it in like that and was amazed that the complainer (compiler) didn't get mad at me. I'm so deep in tree structures mentally at this point and not ready to test yet, but kinda wanted to see if it could work or not. Am I overthinking the issue?
Your Method
override func copy() -> AnyObject {
let clone = super.copy() as SubClassType
return clone
}
My Answer
I'm not sure exactly what you want the method to do.
let clone = super.copy() as SubClassType
statically types the constant clone to be of type SubClassType. It doesn't make any changes to the object. The very next line of code
return clone
statically types the return value to be AnyObject. Again, it doesn't make any changes to the object.
The code is identical to
override func copy() -> AnyObject {
return super.copy()
}
Which is the default behavior when you don't override a method.
In the end, you have 4 lines of code that are identical to 0 lines of code.
class A:NSObject {
var something = "A's something"
override func copy() ->AnyObject {
let copy = A()
copy.something = "A copy's something"
return copy
}
}
class SubA:A {
override init() {
super.init()
self.something = "SubA something"
}
override func copy() ->AnyObject {
return super.copy() as SubA // error'd: EXC Breakpoint fail!
}
}
let a = A()
let subA = SubA()
let b = a.copy() as A
let subB = subA.copy() as SubA
ok really I was being lazy and didn't want to have to do a deep copy but in the end that say's more about me and code after Thanks Giving dinner.
This fails too.
import Cocoa
class A:NSObject {
var something = "A's something"
override func copy() ->AnyObject {
let copy = A()
copy.something = "A copy's something"
return copy
}
}
class SubA:A {
override init() {
super.init()
self.something = "SubA something"
}
override func copy() ->SubA {
return super.copy() as SubA
}
}
let a = A()
let subA = SubA()
let b = a.copy() as A
let subB = subA.copy() as SubA