Why Does Swift Playground Shows Wrong Number of Executions

Why does Swift playground shows wrong number of executions?

It's showing how many times a function / expression is being called on that line:

Sample Image

since the calling expression (summer()) is on the same line, it counts as an extra operation. Hence, 6 prints + 6 returns + 1 summer() = 13 times something happened on that line.

I'm sure I'm not using the correct terminology, but this is what's going on.

Swift playground shows wrong number of executions for statement (forEach on array)

This is quite a confusing situation.

Let's consider the second forEach first:

array.forEach { _ in print("hello") } // (2 times)

Different parts of that line are executed at different times, and Swift counts each of those times as a separate execution. The first time is when it calls array.forEach, and the second time is inside that call to forEach when it executes the call to print in the body of the anonymous function. If we put newlines in, we can see that Swift only executes each line once and reports its “value”:

array.forEach { _ in  // [1]
print("hello") // ()
}

We can also try putting the anonymous function in a variable:

let p: (Int) -> () = { _ in print("hello") } // (2 times)
array.forEach(p) // [1]

Above, Swift executes part of the let p line once to create the anonymous function and store it in p, and another part of the line later to call print inside the body of the function.

Swift reports that the value of the print line is () because forEachs argument must be a function that returns () (the empty tuple, aka Void). Since print already returns (), Swift just lets that be the value of the line.

Before we go back to consider your first forEach example, let's consider one other example:

print("hello"); print("goodbye") // (2 times)

Swift says this line executes two times because each individual statement on the line counts as a separate execution.

So now let's consider your first example:

array.forEach { $0.value } // (3 times)

Let's try it with newlines:

array.forEach {  // [1]
$0.value // (2 times)
}

OK, so the forEach call itself counts as one execution, as expected. But Swift claims it is executing the body of the anonymous function twice. Why?

Recall that forEach's argument must be a function that returns (). But the type of $0.value is not (); it is the internal type Builtin.Int64. So Swift inserts another statement at the end of the line, to return (). Effectively, Swift acts like you wrote this:

array.forEach {    // [1]
$0.value; () // (2 times)
}

And we can prove that by explicitly adding another line to the function:

array.forEach {  // [1]
$0.value // <<<opaque type>>>
()
}

Now Swift thinks each line is executed once, as expected.

Playground shows strange count of execution

It's not telling you how many times the block was executed, but rather how many outputs were called on that line. Since the block returns false and the function allSatisfy returns false, that's 2 outputs in 1 line. You'll notice that no matter the size of the array you get the same value, and if you expand the code, i.e.

intArray.allSatisfy {
$0 < 0
}

you don't see 2 times.

Playgrounds doesn't seem to give a counter for executions of closures/functions passed as parameters, rather only for regular for-loops instead.

Playground wrong output

The reason you are seeing only ["34"] after the types[3..<5] = ["34"] line is because the assignment operator = returns the value that has been assigned.

The other lines show the whole array because the += operator returns the result of the assignment.

Playground execution aborted - EXC_BAD_INSTRUCTION

When you say:

NSString(string: String)

You are trying to create an NSString instance using a String variable named String. But String, is a type, not a variable. So your previous line works because you are passing it a variable:

let newTypeString = NSString(string: str)

But the one where you don't pass an actual variable, but instead pass in a type, fails. Does that make sense?

Update:
It appears that I misunderstood the code as it was originally formatted. The only code the OP was trying to run was:

var str = "Hello, playground"
let newTypeString = NSString(string: str)

According to the provided information, Playgrounds would crash on the second line even though the code was correct. I suggested that the OP try relaunching Xcode to see if that would resolve the issue since Xcode can sometimes be a bit temperamental :) Apparently, that solved the issue.

Swift Playground error: Execution was interrupted, reason: signal SIGABRT

The problem is that you are adding the constraint to stackView rather than containerView.

The documentation for addConstraint states

The constraint to be added to the view. The constraint may only reference the view itself or its subviews.

containerView is the super view of stackView, not a sub view.

If you change your code to add the constraint to the containerView it will run

containerView.addConstraint(.init(item: stackView, attribute: .top, relatedBy: .equal, toItem: containerView, attribute: .top, multiplier: 1, constant: 0))
containerView.addConstraint(.init(item: stackView, attribute: .leading, relatedBy: .equal, toItem: containerView, attribute: .leading, multiplier: 1, constant: 0))

You will probably want to add a trailing and a bottom constraint so that the stack view fills the whole container view. You will, of course, also need to add an arrangedSubview so that there is actually some content in the stack view.

It is generally simpler to add constraints by referencing layout guides rather than this older, more verbose, approach:

import UIKit
import PlaygroundSupport

let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
containerView.backgroundColor = UIColor.white

let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(stackView)

stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true


let label = UILabel()
label.text = "Hello world"
label.textColor = .black
stackView.addArrangedSubview(label)
PlaygroundPage.current.liveView = containerView

xcode 8.3.3 Playground does not show the error next to line number

Please try this menu(although it's already shown):

Sample Image



Related Topics



Leave a reply



Submit