Archive for the ‘Xcode’ Category

iOS Playgrounds: Where is my print output?

Nate writes: “I can’t figure out how to show console output/print in the Swift Playgrounds app for iOS.”

All print output appears in the “sidebar” to the right of the code as little pop-ups:

Screen Shot 2016-06-22 at 1.11.56 PM

Embed the viewer by tapping “Add viewer” so you don’t have to keep popping up the quick view.

The hint box shown (for example “123”, or “?”, or “abc”, etc) depends on the type of item produced. The tiny cube represents an class instance.

Screen Shot 2016-06-27 at 11.40.51 AM

Like desktop playgrounds, you can view a single value at a time or tap the embedded display to select other views like List view:

Screen Shot 2016-06-24 at 12.15.27 PM

Compilation errors appear in-line for main playground code:

http://ericasadun.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-21-at-11.51.25-AM.png

Sources-based errors (which  you cannot yet fix in the app) are shown as popups. When these issues occur, debug back on  your Mac before trying again on iOS.

http://ericasadun.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-21-at-11.29.05-AM-535x401.png

It’s important to remember that the iOS Playgrounds app almost never is running the same version of Swift as you are on the desktop and won’t be until both Swift 3 and iOS 10 go gold.

Want to learn more about iOS Playgrounds? Read Playground Secrets and Power Tips.

Messing with Extensions: Describing color literals for the color blind

As the latest nightly build of Swift refuses to link on my system, I put together a new source editor extension. Developing these is still about as fun as having wisdom teeth pulled (actually the dental surgery would be more fun) but I’ve learned to keep a terminal window open so I can repeatedly delete derived data between builds:

Screen Shot 2016-08-03 at 11.41.33 AM

The new extension looks for a color literal on the cursor line and uses the XKCD color library to describe it.

Devolving your projects

So you moved to 3 and now are suffering from regretsies. Or you’re using Xcode 8 and you want to build a new 2.3 project. Fear not. Here are some tips for all your legacification needs.

Downgrading a Swift 3.0 Project

If you’re feeling especially regretful about moving a project to 3.0, you can downgrade it back to 2.3, but expect work unless you can regress to an appropriate commit. Adjust your build settings to use Legacy Swift (aka Taylor Lautner):

Screen Shot 2016-07-22 at 10.24.46 AM

Building a New 2.3 Project in Xcode 8

Since Xcode 8 doesn’t let you build 2.3 projects, you need to create a 3.0 project. Use build settings to regress to Legacy Swift.

After, make sure to convert all the code back to 2.3. Xcode offers most of the fixits you need for skeleton projects. Be aware that using “Fix all in scope” tends to crash Xcode 8. (27486260).

Screen Shot 2016-07-22 at 10.26.50 AM

Once converted, throw in a for-loop. This ensures that you’re actually running and compiling Swift 2.3 and not Swift 3:

Screen Shot 2016-07-21 at 9.31.42 PM

Importing 2.2 to Xcode 8 as Swift 2.3

If you’re working with an existing 2.2 codebase and are not ready to migrate to a language that has not, as yet, finished its design, you can choose the Swift 2.3 compiler.

First convert the project.

Screen Shot 2016-07-21 at 9.24.41 PM

Next, choose 2.3. The dialog defaults to Use Swift 3, so don’t hit Next until you mentally confirm your choice.

Screen Shot 2016-07-21 at 9.24.47 PM

For many 2.2 projects, you’re ready to rumble.

Screen Shot 2016-07-21 at 9.25.00 PM

Projects that use deprecated APIs and target iOS 10, may need upgrading:

Screen Shot 2016-07-22 at 10.36.19 AM

Explorations into the Xcode Source Editor Extensions underbelly: Part 1

Xcode source extensions are wildly exciting, surprisingly limited, and infuriatingly frustrating to work with. So I thought I’d share some experiences so you don’t have to suffer through some of my issues.

There are bunches of posts around the web on how to create extensions and I really don’t want to dupe their effort. In a nutshell, create a new Cocoa app. Then create a new macOS > Application Extension > Xcode Source Editor Extension target in that app. You’re ready to code.

If you watched the WWDC video, you’ll have seen the whole process of “run the target in Xcode and a new version of Xcode pops up with a darkened label and then you can test your extension”. I’m here to tell you that this approach is a huge steaming pile of crap doesn’t work as well as I’d hoped. What you really want to do is this:

In AppDelegate.swift of your extension/app project, add the following method. It lets you launch the app, install the latest extension and get the hell out of Dodge without using the “Xcode with the darkened label”.

func applicationDidFinishLaunching(_ aNotification: Notification) {
    let alert = NSAlert(); alert.messageText = "Extension installed! Click OK to quit."
    alert.beginSheetModal(for: window) { _ in
        exit(0)
    }
}

In your main extension Swift file (the class defined for XCSourceEditorExtensionPrincipalClass), add this. It lets you watch the OS X console and ensure that your extensions loaded the way you expected them to. Notice that I use NSLog and not print. Always use NSLog, so your output and debug info goes to the system console.

func extensionDidFinishLaunching() {
    NSLog("NAMEOFMYTARGET extensions did finish launching")
}

Set up your Info.plist in a separate editor pane or even a separate window. If you intend to create a multi-part extension (and most people will), you’ll want to build that extension incrementally and slowly add items to your XCSourceEditorCommandDefinitions dictionary. A typical entry looks like this:

Screen Shot 2016-07-21 at 10.20.38 AM

Also, don’t do what I did here. I used “sadun.ExtensionTestbed” because I know this is a throwaway. Assume you may write multiple extension groups and reverse namespace them properly, e.g. “org.sadun.ExtensionName.CommandName”.

Each time you want to test do this:

  1. Build your target.
  2. Open Products, right-click the .app file and show in Finder.
  3. Quit Xcode and run the app.
  4. Launch Xcode.
  5. Open any project that isn’t a playground because Xcode hates me and doesn’t want to properly load extensions for playgrounds. Always start with a non-playground project and *then* open a playground if you want to work with playgrounds.
  6. If the extension is greyed out (and if you follow these instructions they usually aren’t because this is the sequence for El Capitan that appears to be super reliable), check the OS X console. Look for assertion failures, XPC connection failures, and invalidated connections. If you see these, quit Xcode and relaunch. What you want to see there is the “did finish launching” log line.

I know this workflow is a super pain, especially given Apple’s promotion about in-Xcode testing without quitting and relaunching (let alone running the standalone app), but it’s transformed my source editor extension duty cycle from impossible to annoying. A huge win.

Notes:

  • Don’t “clean” your Xcode extension project while running the extension. Ooops.
  • Once the extension crashes, you need to re-run the installer app.
  • I can’t seem to grab a single cursor position, there has to be an actual selection, so my extensions for adding and removing “/// ” for doc comment markup mean you have to select a line, not just move the cursor there. Or maybe there’s a bug that’s screwing this up. I haven’t quite figured this out yet.
  • A lot of my code is super redundant: operate on all lines, operate on all selection lines, operate on selected text. I really need to re-architect a common subclassable system because the actual logic for most plugins is only a few lines or a call-out to another class.
  • Any extension that works on all lines rather than individual selections seems to be more stable in my experience.
  • My experiments trying to create interactive UI elements with extensions hasn’t been going very well, they run in the original application and not in Xcode, the window is behind xcode, they can’t be interacted with while Xcode is running, and you inevitably have to force quit something.

Screen Shot 2016-07-21 at 10.39.39 AM

Here are some things I’ve been messing with. Let me know how your extensions are going for you.

Accessing complete stdlib module declarations

Have you noticed that Command-clicking symbols doesn’t get you the whole stdlib module any more? Instead, you get all these individual submodules:

Screen Shot 2016-07-05 at 11.01.19 AM

Thanks to Mike Ash, I have a workaround.

Step 1: Type `import Swift`

Step 2: Command-click Swift.  *bam*

Step 3. Copy paste the entire thing into a reference file on your desktop. Handy beyond handy.

NOTE: Command-clicking Swift at the top level jump bar (circled) doesn’t work. Radar 27174641

iOS Playgrounds Part 5: Editing real code

While stuck at the Dr’s office, with my daughter being attended to, I decided to try editing a Swift 2.2 playground in iOS Playgrounds, to see if I could upgrade it to Swift 3.0.

The tl;dr is that the tools, while not fully baked, are just as amazing as they were in the WWDC demos. With a few (notable) exceptions, editing source code, invoking fixits, etc. are beautifully realized to the point that I was able to perform non-trivial edits while sitting in a waiting room and using an iPad:

Screen Shot 2016-06-21 at 11.19.54 AM

I was able to fully update this playground page to run and render.

The Good

Built-in fixits are glorious. As in normal Xcode, they update code by inserting missing labels or replacing code:

Screen Shot 2016-06-21 at 11.24.44 AM

Multiple errors are paged (as you can see with the two dots at the top of the complaint), and there’s amazing cross referencing with related items, such as when a protocol is not properly implemented or partially implemented. You just tap away to the error point for the candidate issue.

Number and color edits are fantastic: I didn’t realize you could use the number tweaker to just “dial” your way up and down numbers by continuing to twirl into the number pad:

Screen Shot 2016-06-21 at 11.21.21 AM    Screen Shot 2016-06-21 at 11.21.29 AM

Pages I didn’t expect to work did work! Like this one:  It’s really short. Give it a try. Screen Shot 2016-06-21 at 11.36.42 AM

The Not So Good

You can’t fixit many errors:

Screen Shot 2016-06-21 at 11.30.49 AM

But you can select things and start to type and Playgrounds picks up the context for you:

Screen Shot 2016-06-21 at 11.31.37 AM

The Ugly

Screenshots are for live views, not playground views. And for some reason, I’m having a lot of difficulty today doing screenshots the old way (hold down sleep/wake, then click home). All of these screenshots are from Xcode’s device window instead.

A lot of confusion comes from inappropriate or missing tool tips. Sometimes it leads you down the garden path:

Screen Shot 2016-06-21 at 11.51.25 AM

Screen Shot 2016-06-21 at 11.53.11 AM

What was actually needed looks more like this:

Screen Shot 2016-06-21 at 12.09.44 PM

Trying to edit “advancedBy” to “advanced” by moving the cursor to the end of By and backspacing was simply a no-go. Playgrounds will remove the entire call at once.

You get a lot of problems with 2.2 items needing to be lowercased for 3, or using old CG constructors like CGRectMake not auto-fixing to CGRect(x:y:width:height). Playgrounds just don’t quite get the “fixit” needed for these simple switches.

Screen Shot 2016-06-21 at 12.16.05 PM

Even when you’re typing things in, Playgrounds doesn’t always offer you the right choices. In this example, all this needed was to lowercase CGAffineTransform to cgAffineTransform. No fixit and no syntax match:

Screen Shot 2016-06-21 at 12.12.39 PM

The really cool “drag parenthesis pairs into place” shown in the demos don’t seem to work in the app yet. Instead all I could drag was the letter “j”. (Update: Drag down and left or down and right and then use a second finger to tap or drag the updated key. It is hard but doable. If you’re not coordinated, use two hands. Thanks Seán Labastille)

Screen Shot 2016-06-21 at 11.44.59 AM

You can’t look up module definitions in-place.

No access to Sources that I can find so I can fix errors:

Screen Shot 2016-06-21 at 11.29.05 AM

The live views are distorted:

Screen Shot 2016-06-21 at 12.18.46 PM

Screen Shot 2016-06-21 at 12.19.23 PM

But other than that, wow, what a cool tool. I’m really enjoying it a lot.

Sorting and sharing playground pages

Sorting Playground Pages

If you keep a lot of playgrounds on hand in a single file (I do!), you may find it handy to sort your pages alphabetically. Use Edit > Sort > By Name to clean up your organization.

Screen Shot 2016-01-04 at 10.07.27 AM

Hopefully you’ve named each page logically, for quicker scanning.

Screen Shot 2016-01-04 at 10.08.16 AM

Unfortunately, as you add pages to playgrounds, Xcode performance takes a massive hit. While you can re-order by dragging, that starts to become impractical once you hit a couple of dozen playgrounds.

Copying Playground Pages

It can be simpler just to drag copies of a page into a new workspace with better performance. This screenshot shows dragging the “adding arrays” page over to a new playground file.

Screen Shot 2016-01-04 at 10.18.15 AM

You can also open a playground package (Control-Click/Right-Click > Show Package Contents) and access individual source files however you like.

Screen Shot 2016-01-04 at 10.22.04 AM

You cannot drag and drop these between packages unless you’re willing to start editing the contents.xcplayground XML. It’s not difficult, but it’s generally not worth your time.

Instead, consider opening the page in a text editor, and using copy/paste into a new page you manually add to another playground.

Searching Playgrounds

Xcode offers two search fields to help you locate material. The bottom search bar matches page names:

Screen Shot 2016-01-04 at 10.15.09 AM

The search at the top of the navigator finds matching text.

Screen Shot 2016-01-04 at 10.13.47 AM

Searching Playgrounds from the Command Line

A while back, I wrote pggrep to find playground files, which were not otherwise indexed by spotlight. Given how much material ends up in playground testbeds, pggrep has been a valuable tool for finding where I had explored some topic or another in the past.

Book

There’s also a book on all things Playground.

Updated linter

Just updated my testlint project (http://github.com/erica/testlint) to start searching for Swift 3.0 issues. For example, SE-0003 will remove var parameters. So this will no longer compile:

 if var testStream = OutputStream(path: aPath) {
     print("Testing custom output", toStream: &testStream)
     print("Hello ", terminator: "", toStream: &testStream)
     print("World", toStream: &testStream)
     print("Output sent to \(testStream.path)")
 } else {
     print("Failed to create custom output")
 }

Instead, you’ll need to use if-let and create a var inside the success branch.

if let outputStream = OutputStream(path: aPath) {
    var outputStream = outputStream
    print("Testing custom output", toStream: &outputStream)
    print("Hello ", terminator: "", toStream: &outputStream)
    print("World", toStream: &outputStream)
    print("Output sent to \(outputStream.path)")
} else {
    print("Failed to create custom output")
}

My linter started off as a complete hack, in response to SwiftLint‘s minimal beginnings. I kept working on the repo because (1) I had complete control over it and (2) it offered many more rules that I found valuable. It’s still a complete hack but it’s evolved into a way I can explore style rules in preparation for writing Swift Style.

It is still not a great linter (it goes line by line instead of parsing because I didn’t want to use inter-process hacking and it relies on regex, waving my hands, chicken entrails, etc). However, it’s been an amazing way to start thinking about the way I do and should write Swift.

I think you’d probably get more out of my comments in Linter.m than via daily use. Just thought I’d let you know that it was updated.

How to compile with Xcode and Swift 2.2

Tonight, I decided to kick the wheels of Swift 2.2 from inside Xcode. I knew it was possible but it took me a while to figure out the exact directions as I was thinking I needed to updated the compiler in the build phases, not launch Xcode with a different toolchain. Turned out I should just have read the instructions better.

Here are the steps:

Install Swift 2.2 First install Swift 2.2, following the directions from swift.org. When I checked a few minutes ago, the links were down so you may have to wait until tomorrow. There’s a pkg installer and the setup process is simple. Make sure you quite out of Xcode first.

I had to adjust the initial instructions slightly as I run tcsh and not bash (I know, I know). I have my 2.2 Swift set up as a symbolic link for ease-of-reference.

lrwxr-xr-x 1 ericasadun staff 68 Dec 3 09:19 swift22@ -> /Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swift

Test Swift 2.2 Execute Swift to make sure the proper version is installed (you’ll see this in the first line) and then quit out.

% swift22
Welcome to Apple Swift version 2.2-dev (LLVM 46be9ff861, Clang 4deb154edc, Swift 778f82939c). Type :help for assistance.
 1>

Launch Xcode From the command-line, with Xcode closed, use xcrun launch-with-toolchain to select the toolchain you wish to rely on.

% xcrun launch-with-toolchain /Library/Developer/Toolchains/swift-latest.xctoolchain/
Verifying toolchain code signature...

Verified signature.

Launching Xcode...

2015-12-03 18:28:26.354 Xcode[9728:2177144] Build settings from command line:
2015-12-03 18:28:26.354 Xcode[9728:2177144] ENABLE_BITCODE = NO
2015-12-03 18:28:26.354 Xcode[9728:2177144] SWIFT_DISABLE_REQUIRED_ARCLITE = YES
2015-12-03 18:28:26.354 Xcode[9728:2177144] SWIFT_EXEC = /Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swiftc
2015-12-03 18:28:26.354 Xcode[9728:2177144] SWIFT_LINK_OBJC_RUNTIME = YES
2015-12-03 18:28:26.354 Xcode[9728:2177144] XCODE_DEFAULT_TOOLCHAIN_OVERRIDE = /Library/Developer/Toolchains/swift-latest.xctoolchain (etc)

Have fun. Although the revised Swift Programming Language states in its Document Revision History that several features have been removed from discussions, I was still able to compile with them. I tested variable function arguments, ++ incrementors, and currying. I assume these will be removed later.

Updated for Swift 2.2.
Removed discussion of var patterns, variable function arguments, and the special syntax for curried functions.

Skip playgrounds. You cannot use the 2.2 toolchain for playgrounds. (“The toolchain currently being used for debugging is not compatible with playgrounds. Relaunch Xcode with the default toolchain to use playgrounds)

Screen Shot 2015-12-03 at 6.42.27 PM

To conclude: I’ve put a standard library dump here. This includes both module declarations and 2.1/2.2 diffs.

Deducing your playground “device”

When your playground doesn’t find the exact device it wants to simulate it gets cranky. When your playground gets cranky, it displays this error, which more or less tells you nothing about which run destination to install:

Screen Shot 2015-11-22 at 6.05.21 PM

So what are you supposed to do?

The easiest solution is to hop into Xcode > Windows > Devices and add one of every kind of possible simulator so Xcode stops throwing fits. Quit and restart and Xcode loses that wild-eyed crazy look and playgrounds start behaving…better.

But say you’re of a parsimonious frame of mind. Imagine those extra simulators offend you with their patent lack of efficiency. Which simulated devices can you toss from Xcode?

  • Well, if you’re going to do any Apple TV dev, don’t toss the Apple TV one.
  • You don’t need a “simulator” for OS X dev. So you probably never got an error in the first place.
  • But what about for general iOS development? Which one was right?

Easy way to find out: print(NSTemporaryDirectory()). It will look something like this:

/Users/ericasadun/Library/Developer/XCPGDevices/9A03F9FE-79F4-4FEA-B180-AB0D454C9A61/data/Containers/Data/Application/004CC333-1E33-4E20-AFEC-A8A5B7778562/tmp/

Then hop into the XCPGDevices folder to the subfolder with that UUID, and open the property list.

{
 UDID = "9A03F9FE-79F4-4FEA-B180-AB0D454C9A61";
 deviceType = "com.apple.CoreSimulator.SimDeviceType.iPad-Pro";
 name = "iPad Pro";
 runtime = "com.apple.CoreSimulator.SimRuntime.iOS-9-2";
 state = 3;
}

Boom. This instantly told me that the one simulator I couldn’t toss for iOS  playgrounds was the iPad Pro one.

There’s, of course, not a lot of harm in keeping a bunch of simulators around — and they can be extremely helpful to have on hand. But some deeply OCD part of me is now relieved that I know which simulator my playground is running on. I hope this will comfort some of you as well.