Category Archives: Swift

Viewing console output in iPad Swift Playgrounds

I’m learning Swift and SwiftUI, and as part of this journey I’m working my way through Donny Wals‘ excellent Practical Combine: An introduction to Combine with real examples!

The problem

I’ve been working on my 11″ iPad Pro running iPad OS 13.5.1, with the book open on one half of the screen and Swift Playgrounds on the other, and I’ve noticed that the results from calls to print in Combine callbacks are not output on my iPad:

A Workaround

I worked around this by just entering the variable name:

Another problem

This feels like a bug to me, but I had a good workaround. Until, that is, I wanted to use the Combine print function. I needed to see that output.

This is what Donny’s book showed, and what my iPad Swift Playground showed:
Combine print showing nothing

The console output was lost for the prints both in the reactive chain and in the sink. Googling gave me no obvious answers.

When learning, this is exactly the kind of thing I like to dig into, and try solve.

A solution

This is the solution I came up with:

import Combine

class PlaygroundConsole : TextOutputStream, CustomStringConvertible {
    var text = String()
    func write(_ string: String) {
        text.append(string)
    }
    var description : String { text}
}
let console = PlaygroundConsole()

// Based on https://stackoverflow.com/a/47223166
func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    let output = items.map { "\($0)" }.joined(separator: separator)
    console.write(output + terminator)
}

I added a TextOutputStream which I could pass to the Combine print and I shadowed the global print function to write to the same stream. The implementation simply stores up the text, and it can then be output at the end.

If I change the Combine print to send it’s output to the PlaygroundConsole and then examine the console variable’s content at the end, this is what I see:

Note the modified .print(to: console) in the Combine chain.

Disclaimer: I’m new around here

As I said, I am new to Swift. This is a very simple solution, but hopefully it will help someone else too.

This could already be a solved problem, and I didn’t stumble upon it when Googling. Also, the above code is newbie code – feel free to let me know of any mistakes or non-idiomatic code (I’ve been doing C# for many years).

In any event, if you are also learning Swift and SwiftUI and want to start from the beginning using Apple’s Combine framework, Practical Combine is a great way to learn.

WatchKit Error – unable to instantiate row controller class

Trying to create a simple WatchKit table, I hit the error shown in this blog post title.

You mileage may vary, but the eventual cause was that when I added my custom RowController class I accidentally added it to the wrong module … I added it to the main iOS app (WatchTest) instead of the Watch extension:

image

The first hint of this was when I was trying to reference the RowController when calling rowControllerAtIndex, and my custom row controller class could not be found:

var rootRow = rootTable.rowControllerAtIndex(0) as RootRowController

By this time I’d already set it as the RowController class for my table’s row in the storyboard, and had inadvertently referenced the wrong module:

image

I fixed the compilation error by adding my custom RowController to the Watch extension module, but accidentally added it to both modules:

image

Everything compiled but when I ran the log shows the error from the title: Error – unable to instantiate row controller class

image

I eventually figured out my mistake, and made sure that the row controller only belonged to the extension module:

image

And I made sure the correct module was referenced when defining the RowController in the storyboard:

image

It would be nice if the Watch App’s storyboard only saw classes in the Watch Extension’s module.