Archive for the ‘Xcode’ Category

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.

Speeding up Swift playgrounds with closure initialization #swiftlang

Swift playgrounds can be ridiculously slow, especially when you’re working with items sourced from SpriteKit and SceneKit. Moving any and all code you can into an external Sources file enables optimized compilation and far better runtime speed.

The big problem with this approach is that you lose the linear flow that you have in playgrounds. Module compilation does not support top level directives that modify variables. So, for example, if you have code that looks like this:

 public let lightNode = SCNNode()
 lightNode.light = SCNLight()
 lightNode.light!.type = SCNLightTypeOmni
 lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
 scnscene.rootNode.addChildNode(lightNode)

(I apologize for the forced unwrap. This was taken from Apple sample code.) 

You cannot move these lines directly to a module file because you’re using top-level calls, which will not compile in an external swift file. As a workaround, you might throw most of that into a function, like this:

internal func setupLightNode() -> SCNNode {
 let theLight = SCNNode()
 theLight.light = SCNLight()
 theLight.light!.type = SCNLightTypeOmni
 theLight.position = SCNVector3(x: 0, y: 10, z: 10)
 scnscene.rootNode.addChildNode(theLight)
 return theLight
}

And then call it from your declaration:

let lightNode = setupLightNode()

That’s ugly. It creates an unnecessary extra function and it forces you to place the code that processes a new instance before the instance itself is declared.

Closures offer a (slightly) more appealing solution, as you see in the following example. Here, the initialization lines are wrapped together into a single group, and executed, returning the fully initialized instance at the end.

// create and add a light to the scene
public let lightNode: SCNNode = {
  let theLight = SCNNode()
  theLight.light = SCNLight()
  theLight.light!.type = SCNLightTypeOmni
  theLight.position = SCNVector3(x: 0, y: 10, z: 10)
  scnscene.rootNode.addChildNode(theLight)
  return theLight
}()

This approach enables you to build and initialize an item using a single statement, retain the flow and readability of your playground declarations, but run things quite a bit faster.

Here’s a video of this lightNode code in action, running along with various other setup tasks. After hitting the playground “run” button, it now only takes about 3-4 seconds to get going instead of minutes. This kind of speed-up means it becomes far more practical to prototype SpriteKit and SceneKit elements in playgrounds before deploying them to real apps.

Update: Here’s another approach for setting up class instances:

infix operator •-> {}

// prepare class instance
func •-> <T>(object: T, f: (T) -> Void) -> T {
  f(object)
  return object
}

class MyClass {var (x, y, z) = ("x", "y", "z")}
let myInstance = MyClass() •-> {
 $0.x = "NewX"
 $0.y = "NewY"
}

What do you think?