Feeds:
Posts
Comments

Posts Tagged ‘Apple’

I’m big on education, think Swift is a great language, and believe games can be a practical way to motivate learning. So, how did I put this into practice?

What’s My Motivation?

During my career, I’ve had the opportunity to teach programming and software development (two distinctly different things) to both teens and adults. One thing that’s always struck me is the disjoint nature of the material. Not in terms of the subject matter, but rather with respect to the examples being used. I learning a spoken language, you don’t abandon a part of speech as you acquire another. Learning is both cumulative. As we learn, we revise our approach.

In teaching programming, we seem to be so focused on being focused, that we divorce ourselves from the actual processes that go on when we solve real-world problems. In the past few years, I’ve noticed that people are producing programming language courses reduced to five minute info-bites. Here’s the thing, software development is a long-form practice.

Early Insight

I put together my first programming curriculum in 1981 when I was a instructor at Computer Camp, Inc. in Santa Barbara, California. The students were teens and the problem in my mind was motivation. Unlike adults, most of the teens I’ve taught over the years don’t approach programming from experience. They have a beginners mind. This is both good and bad for a teacher. The good is that they don’t have bad habits yet. If properly taught, they will think in the language. The bad is that we, as experienced developers, have come to see programming languages as a collection of “computer language components” and not as a methodology for solving problems as expressed in a specific syntax. As a result, the vast majority of software written today would have the spoken equivalent of transliteration. All the words are there and a native speaker could probably make sense of it, but they would suffer greatly.

In 1982, I found myself tasked with teaching an advanced BASIC programming class. It was then that I hit upon the idea of a dungeon crawler. The students were interested from the outset. They appreciated that everything they were spending their precious time on was leading to the outcome. They looked at the language as a means to solve a problems and not a way to take a solution from another language and reapply it.

So, now I understood that it was possible to motivate and teach people how to think in a programming language. Could I leverage this understanding?

Teaching Revisited

In 2008 I had the opportunity to teach electrical engineers C++ and SystemC. These were individuals who’s software development experience was grounded in C programming. Their code and indeed, approach to software development, was procedural as once might expect. In order to teach them SystemC, people must first learn C++ (the language SystemC is written in). After working with the materials we had been using, I felt strongly that we weren’t motivating an appreciation and understanding of object orientation. I had the opportunity to participate in the creation of an entirely new C++ curriculum. From the beginning it introduced object orientation. There is a interesting shift that takes place when the responsibility for the data shifts from all the code that touches it to objects that manage it.

The Stanford Way

I’ve been watching Stanford’s iOS development course (CS193P) since it was first made available. It has undergone an interesting evolution over the past decade. Initially, it taught Objective-C development and iOS programming. This included pure (non-GUI) Objective-C and test driven development. With the fundamentals in place, the model-view-controller paradigm was taught as the foundation of iOS development. Then the class shifted into the standard piece-part methodology we see everywhere, albeit with a distinctly iOS bent.

Over the years, both the pure language and test driven development aspects went away. These were relegated to reading material. Objective-C was supplanted by Swift. More sophisticated areas were covered as the iPhone evolved. By the end of the course, students can build complex apps. But it feels like people are learning APIs rather than the language. But what can you do in 10 weeks? Would people actually pay for a college course to learn Swift and then another for iOS development?

Enter Wumpus

About five years ago, someone asked me to teach them how to make iPhone games. They had no software development experience and little desire for the traditional approach of learning via classes or books. They understood the ins and outs of game play and had a keen sense of what made a game playable.

The process that followed was the condensation of forty years of writing code and developing software. Today, when we work with just about any OS API, we have to deal with a context. But how do you motivate the very idea of the context. How do you teach people to work effectively with the net result of over fifty years of software development practices without just expecting that people will simply accept that this is the way it is and you just have to accept it? You can easily create an animation, but what is happening behind the scenes? Being able to understand and explore these questions is what will determine if someone will be capable of working beyond the software equivalent of writing pulp fiction.

In the end, I settled on teaching software development through the very old game of Hunt the Wumpus. This game appeared in the original Unix distributions. It has simple rules, a bit of action, some random elements and is, on the whole, able to be understood by a nine-year-old. It’s implementation can be used to demonstrate multi-dimensional arrays, randomization, object-orientation, internationalization, error handling, data visualization and testing.

As this was before Swift, it was implemented in Objective-C.

Personally, I used my implementation of Wumpus to experiment with iOS. Specifically, I was tinkering with storyboards in Xcode. I wanted to see if it was possible to implement the user interface of Wumpus entirely using scenes representing the rooms within the game. This is, of course, a horrific abuse of the scene concept and is the equivalent of unfolding an array of objects into individual routines. It did, in fact, work. And I would not ever recommend that the technique be used for production code.

Enter Swift

Two years ago Apple announces Swift. Immediately, I started working with it. Like many languages before it, Swift incorporated lessons learned. In the case of Swift, many lessons were learned. You can look at my earlier posts to see my past musings on the language.

In May, I found myself with sufficient time on my hands to undertake a rewrite of Wumpus in the soon to be released (now just released) Swift 3. Concurrently, iOS 10 was to come out and would be supported by Xcode 8. Changes all around. My initial Wumpus model was readily brought over from Objective-C. Over time I realized that many of the things in that implementation could be completely folded down to a single line of Swift code. Swift wasn’t an extension of an older language. In fact, as the language evolved from version 1 to 3, many elements initial present were removed or replaced. Today’s Swift is much more consistent as a result.

I knew the pieces of the user interface that would be required and set about recreating them. This time is a sane fashion. Once this was done, I began the process of connecting the view to the controller layer and eventually the model. All the while, adopting the Swift 3 and iOS 10 idioms.

At this point, I had a playable version of Wumpus. There was a main scene that took you to the rules or the game. The rules were a static chunk of text. The credits was static attributed text. You could navigate the maze and be moved (scene with alert) or die (scene with alert). Shooting came in and initially used a scrolling picker with the room numbers. Dull stuff.

Just Add … Everything

Now came the interesting bits. The iOS-specific bits.

It’d be dull to cover this in detail, so here’s a rough sequence.

  • 30+ background images
  • danger annunciator images
  • tint overlay to gray scale backgrounds
  • ambient sound across scenes (looped soundtrack)
  • incidental sounds within scenes (looped for danger and one-shot for events [moved, died])
  • added settings controls for all audio volumes
  • asset catalog used for both image and sound management (simplified access)
  • rebuilt settings using a table with dynamically constructed cells with action handlers
  • saved statistics using class-based archiver
  • rebuilt statistics using dynamic data generation from the statistics data
  • segues and segue unwinding (navigation control)
  • timers (scene auto-transition from title scene)
  • tap gestures (eliminating navigation buttons)
  • replaced static rules text with chunked pages and swipe gestures
  • custom font (Kalam)
  • parallax (titles, danger annunciators and event imagery)
  • dynamically constructed attributed text (credits)
  • endless scrolling text loop (credits)
  • dynamically constructed tables from plist data (statistics field names)
  • static collection view replacing lame picker interface (shoot scene)
  • app analytics (Firebase)
  • ad support (AdMob)
  • JSON processing (credits source import)
  • core data (credits attributed string construction)
  • built to work with both iOS 9.3 and 10.0 (core data had a major change)
  • social network (Facebook / Twitter) posting

Testing, Testing

An important part of creating an iPhone application is being able to ship it. But before that you should really test it. A lot. Really.

To do that you need to do the dance of getting certificates and creating an app instance. With these you can push builds to Apple’s servers where they can be accessed by internal testers (all builds) and external testers (specific builds, after review [sort of]). Then comes the great fun of prodding the testers.

Collateral Damage

It’s been tested. All the features (for this release) are present. And it’s time to ship, right? Actually, no. You can’t ship an app without creating a bucket and a half  of collateral images (screenshots) for the app store. There’s also the small matter of the web site that will support the app. And no self-respecting app would go up without a game play video.

About those images. You technically only need one set at the highest screen geometry. The others will be generated by scaling. Now, you’ve gone to all the trouble of adopting an adaptive user interface so things look reasonable on all the various screen geometries, so not generating imagery for every size would just be lazy. Happily, all these can be generated from simulator screen capture. Image having to round up half a dozen devices just to do screen caps. Did I mention that video? Well, you can’t video capture from the simulator. So, for those of you who look at my app on the store, there’s just the one from my current iPhone.

I do keep referring to Wumpus as an iPhone app. Well, it is. I designed it for portrait-only. Now this doesn’t prevent you from putting it on an iPad. The problem is that Apple has never updated the screen size used from iPhone apps on an iPad. It’s this pointlessly scrunched up screen size. It looked brain dead. So, I went back and tweaked the layout to be less egregious. It’s not pretty, but why are you running it on an iPad in the first place?

Can I go now?

What could possible be left to do?

  • specification of age rating
  • description for the store
  • verification that you own or have license for all the bits you’re using
  • text for alerts presented to the user, if certain features are used

About that whole licensing point. Wumpus uses a lot of images and audio tracks. They all need to be acknowledged properly. That was a driving factor in using Core Data to track them. All the ones I used were either public domain or minimally encumbered. The biggest problem I had was not finding them, but selecting from among them.

And yes, now it’s ready to ship.

Ship It

So, about two weeks ago, submitted Wumpus for review. Well, I tried to. Apple will only review apps built against finalized OS libraries. Wait. Wait. So I added a few more bits to fill the time. On Monday 12 September 2016, I was able to submit Wumpus for review. After a brief diversion of trying to find out how to answer new privacy questions related to the use of Firebase and AdMob. Then came the wait. Did I forget something? Was there some horrible error condition lurking waiting for the mystical Apple auto application checkers to detect. Would the review be delayed by more relevant applications (honestly, that’s just about every other app)? Nah, it was all good.

On Wednesday 14 September 2016, I got an auto-generated email informing me that my app was available for sale. Pretty anti-climactic really. If you have an iPhone/iPad, you can download it today. The related web site is also online.

And?

So where’s the tie-back to the teaching programming / software engineering? That was the point, right? Absolutely. I’m not done. Although Wumpus represents an interesting résumé piece and I’ll be extending it with additional technologies (such as web, Apple Watch), my take away is an example that I know I can use to teach both Swift and iPhone development. Like all good stories, this one leaves me wanting more.

Read Full Post »

iOS 10 ships on September 13th. Apple has changed their generated code for Core Data. It doesn’t compile if you set your deployment target to iOS 9.3. What’s a developer to do?

For a very long time now, Apple has be proud, and deservedly so, that their users are overwhelmingly keeping up-to-date with the latest releases of their operating systems. As such, Apple’s messaging to developers is to support the current and previous OS version. Most of the time, this isn’t a big deal. Sometimes, it is. With the latest changes related to Core Data, it’s a problem.

If you create a new Xcode project that will being using Core Data, you get some useful code bits in the AppDelegate. In Xcode 8, you get the following (comments removed for brevity):

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "coreme")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
 func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}

This works great if you’re only going to build for iOS 10, but if you try to set your deployment target to iOS 9.3 as recommended, you’ll get the following error:

AppDelegate.swift:49:35: 'NSPersistentContainer' is only available on iOS 10.0 or newer

Well, that’s not good.

As users of Core Data know, operations using it use a database context. You can see it being used in the saveContext function above. Here we see that the context is a member of the persistentContainer. Since this doesn’t exist in iOS 9.3, we’ll have to get it some other way.

Let’s look at what used to be supplied with Xcode 7 (udpated to Swift 3):

lazy var applicationDocumentsDirectory: URL = {
    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return urls[urls.count-1]
}()

lazy var managedObjectModel: NSManagedObjectModel = {
    let modelURL = Bundle.main.url(forResource: "bfoo", withExtension: "momd")!
    return NSManagedObjectModel(contentsOf: modelURL)!
}()

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator =
{
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
    
    do {
        try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
    } catch {
        let dict : [String : Any] = [NSLocalizedDescriptionKey        : "Failed to initialize the application's saved data" as NSString,
                                     NSLocalizedFailureReasonErrorKey : "There was an error creating or loading the application's saved data." as NSString,
                                     NSUnderlyingErrorKey             : error as NSError]
        let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        print("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
        abort()
    }
    
    return coordinator
}()

lazy var managedObjectContext: NSManagedObjectContext = {
    let coordinator = self.persistentStoreCoordinator
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    return managedObjectContext
}()

I’ve left out the saveContext function as it’s only distinction is where it gets the context from. Above, we see that the context is a separate variable.

Now without a doubt, the iOS 10 code is much simpler, but, if we want to be able to do the right thing and support both current and last version, we need a bit of a mash up. It’s a bit tedious, but you only have to build it once (hint, hint Apple). Here’s what I’ve come up with.

// MARK: - utility routines
lazy var applicationDocumentsDirectory: URL = {
    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return urls[urls.count-1]
}()

// MARK: - Core Data stack (generic)
lazy var managedObjectModel: NSManagedObjectModel = {
        let modelURL = Bundle.main.url(forResource: modelName, withExtension: modelExtension)!
        return NSManagedObjectModel(contentsOf: modelURL)!
}()

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let url = self.applicationDocumentsDirectory.appendingPathComponent(modelName).appendingPathExtension(sqliteExtension)

    do {
        try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
    } catch {
        let dict : [String : Any] = [NSLocalizedDescriptionKey        : "Failed to initialize the application's saved data" as NSString,
                                     NSLocalizedFailureReasonErrorKey : "There was an error creating or loading the application's saved data." as NSString,
                                     NSUnderlyingErrorKey             : error as NSError]
        
        let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        fatalError("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
    }
    
    return coordinator
}()

// MARK: - Core Data stack (iOS 9)
@available(iOS 9.0, *)
lazy var managedObjectContext: NSManagedObjectContext = {
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)    
    managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator    
    return managedObjectContext
}()

// MARK: - Core Data stack (iOS 10)
@available(iOS 10.0, *)
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: creditsModelName)    
    container.loadPersistentStores(completionHandler: {
        (storeDescription, error) in
            if let error = error as NSError?
            {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    )
    
    return container
}()

// MARK: - Core Data context
lazy var databaseContext : NSManagedObjectContext = {
    if #available(iOS 10.0, *) {
        return self.persistentContainer.viewContext
    } else {
        return self.managedObjectContext
    }
}()

// MARK: - Core Data save
func saveContext () {
    do {
        if databaseContext.hasChanges {
            try databaseContext.save()
        }
    } catch {
        let nserror = error as NSError
        
        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
    }
}

I’ve introduced databaseContext as the context variable to be used throughout. I think it’s more clear and now saveContext doesn’t have to care which OS you’re targeting. With this change in place, you can now safely target 9.3 and still build for 10.0.

Read Full Post »

One of the challenges in learning a new language, be it human or computer, is learning to think in the language. Learning Swift is no different.

I’ve been spending the past several months working on the first iOS (iPhone) app that I’ll be releasing through the Apple app store. I’m writing it entirely in Swift 3, the latest version of the language. Yesterday, I was looking over the code to see if there were any places where I’d been thinking in a non-Swift fashion. This moment of reflection was triggered by my viewing of a very recently released class in Swift from one of the major online education sites. I was disappointed that the instructor was using an idiom that I knew was easily simplified in Swift. My disappointment made me wonder if I had similar issues.

The following is actual code from my upcoming app. I had originally created it’s core in C as an extensible example for teaching that language. The setup is as follows:

  • the map is an array of connections from each room
  • the number of connections from each room is fixed
  • we are explicitly tracking the number of a given type of hazard

We want a function that returns true if there is hazard in one of the connecting rooms. Here’s the original code:

var hazardNear = false
        
if hazardCount > 0
{
    for nextRoom in 0 ..< numberOfConnections
    {
        if hazardRooms.contains(exits[room][nextRoom])
        {
            hazardNear = true
                    
            break
        }
    }
}
        
return hazardNear

Pretty conventional C-esque stuff. The first thing that jumped out at me was the reliance on knowing the number of connections. Swift arrays are true collections. Let’s treat them as such.

var hazardNear = false
        
if hazardCount > 0
{
    for nextRoom in exits[room]
    {
        if hazardRooms.contains(nextRoom)
        {
            hazardNear = true
                    
            break
        }
    }
}
        
return hazardNear

When viewed this way, it’s obvious that we’re just filtering the collection based on a condition. So, just do that.

var hazardNear = false
        
if hazardCount > 0
{
    hazardNear = exits[room].filter{hazardRooms.contains($0)}.count != 0
}
        
return hazardNear

We’re filtering the array of rooms for ones that contain the hazard and checking for a non-zero count. But this is still a bit clunky. Let’s examine what we’re really asking.

var hazardNear = false
        
if hazardCount > 0
{
    hazardNear = !exits[room].filter{hazardRooms.contains($0)}.isEmpty
}
        
return hazardNear

It’s far more clear to simply ask if the filtered array is non-empty directly. What’s left is one final simplification.

return hazardCount > 0 && !exits[room].filter{hazardRooms.contains($0)}.isEmpty

One might ask whether having an explicit count is necessary as the hazard array has a count. True. Although the hazard array is built based on the number of hazards, so I still need it to be around.

Overall, I fairly pleased with the results of the exercise. In the end, the code is much clearer in intent.

Read Full Post »

One of the things I’ve always liked about Apple is the way they revisit and revise their tools. Although there is comfort in logging on to any *nix system and knowing that ed or vi or gcc will be there, I believe that the lack of investment in standard tools hurts more than knowing that anyone who has written code since 1980 will still be at home. This is the technical equivalent of having a rotary gang switch to change channels on your flat-screen TV because that’s what your grandparents were used to and they still need to use the TV. You know what, they managed to adapt to there being a wireless remote and 500 channels.

Swift is probably the most visible of today’s Apple tool changes. As we fast approach the release of Swift 3.0, it’s good to check in and see what the future of software development of Apple products is going to be like. This is one of those growth and pain stories.

From the language standpoint, Swift 3.0 brings a greater level of consistency in terms of behavior and style. Compared to other languages, new developers will have fewer exceptions to keep track of. For those following the latest Stanford iOS class on iTunesU (CS193P) thinking that when they’re done that they’ve learned Swift, well, sorry, but in a few months you’ll need to update all your code.

One of the biggest changes in Swift 3.0 is the way that the Apple OS-specific libraries are handled. In the same way that C++ and Python aren’t bound to a particular operating system, neither is Swift. You don’t need to be on MacOS or iOS to use Swift. The problem is that most applications that interact with people need to be bound to some kind of operating environment. On Windows that’s typically done by using .Net. With Java, you’ve got a laundry list of environments (EE, SE, ME). For Swift, you’re binding to Apple’s plenitude of support libraries. All of which have, for the past decade or so, been based on Objective-C. The great thing about new languages is that they incorporate lessons learned. The devil of them is that vast body of existing code they need to interface to.

In the case of MacOS and iOS, the libraries make a lot of sense if you’re writing code in 2004. We’ve learned a lot about languages and frameworks and operating systems since then. But, as with all things, there are only so many hours in the day. Inevitably, you build a core around the language and, if you’re nice, create bridges (shims) to the external bits. If you’re Apple, you’re usually particularly nice and create toll-free bridges (ones built for you). If you’re Microsoft, you have the joy of multiple layers of conversions to look forward to. Eventually as the language evolves, you get to the point where the rules you gave people as to how the bridging worked do align with the language. That’s where we are today with Swift 3.0.

So, by now, you’re saying to yourself that this must be really bad to merit such a long preamble. Sort of. I came across a nifty article on what’s new in Swift 3.0 and decided to download the May 9th Swift trunk [see update below] and see for myself. There’s a nifty video from the same person. He does a good job of covering the changes. Remember my earlier reference to the Stanford class? I’ve been following it myself. I thought, “let’s see how what’s being taught tracks.” For my first attempt I chose a small app that uses gestures to tinker with a face drawn to the screen. Now as those of you familiar with iOS will be aware, there are two ways of implementing UI binding to code. You can either write it in code or use Interface Builder. The thing about using IB is that it handles a bunch of tedious details for you. It also hides stuff and is the source of weird errors if you screw things up.

In implementing this app, I of course used IB. And you know what, I crashed and burned. After installing the new tool chain and restarting Xcode, my modest app showed a variety of error stemming from the changes in Swift 3.0, all of which were easily corrected thanks to the very clear error messages and suggested remediation provided. The app launched and drew the baseline image, but any gesture failed miserably. Maybe it was the project. I created a new project with nothing but a raw view and added a tap recognizer in IB and wired it up to the view with a print diagnostic. It happily built, but also crashed on tap.

2016-05-26 15:16:31.150 f2[21677:736529] -[f2.ViewController tap:]:
  unrecognized selector sent to instance 0x7ffe59d31eb0
2016-05-26 15:16:31.156 f2[21677:736529] *** Terminating app due to
  uncaught exception 'NSInvalidArgumentException', reason:
  '-[f2.ViewController tap:]: unrecognized selector sent to instance
  0x7ffe59d31eb0'

Creating the action in code worked. To be fair, this tool chain is coming from the Swift site and not Apple. I then checked to see what happened if I tossed in a vanilla button. Same problem. That wouldn’t do. The answer turned out to be held in the AppDelegate. As it happens the new tool chain generated a warning for each of the standard boiler functions.

/Users/charleswilson/Documents/projects/2016_CS193P/FaceIt/FaceIt/
  AppDelegate.swift:17:10: Instance method
  'application(application:didFinishLaunchingWithOptions:)' nearly matches
  optional requirement 'application(_:didFinishLaunchingWithOptions:)' of
  protocol 'UIApplicationDelegate'

The provided code reads:

func application(_ application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)
  -> Bool

It seems that the functions need additional decoration. The warning notes that the function nearly matches. Allowing FixIt to do its thing yeilded:

@objc(application:didFinishLaunchingWithOptions:)
  func application(_ application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)
  -> Bool

Apparently, additional decoration is required to bridge properly. So I went back to the standard IB added recognizer. Here’s the action.

@IBAction private func tap(sender: UITapGestureRecognizer)

Once the objc decoration is added, all is well.

@IBAction @objc(tap:) private func tap(sender: UITapGestureRecognizer)

Not a big deal to make the correction once you realize what’s required. Hopefully, others will take this as a heads up and not be bogged down as they update their code.

Overall, I have a high degree of confidence in Swift 3.0, the changes make the language better. So, go get it yourself and see the future of Apple software development.

2016-06-05 Update

I pulled the May 31 Swift trunk with the same results. I’d imagine that Apple will clean this up really soon as WWDC is just around the corner.

2016-06-09 Update

I pulled the June 6 Swift trunk and got the same results. Cutting it close for WWDC.

Read Full Post »

HackerRank has become a popular showcase for software developers. Its many participants have the ability to choose their language. Recently Apple’s Swift language has been added.

This is all well and wonderful, but as I written about in previous posts, non-UI oriented use of Swift has not been a priority. It’s not impossible, but you have to scrounge for the bits you need to use it.

As those who have used HackerRank know, non-UI is the way of things. So, here are a few bits that make it possible to use Swift in the HackerRank.

Note: In production code, one should always check when unwrapping variables. In HackerRank, input will be well-behaved and the focus is on the internal workings rather than the input mechanism.

Reading a string from the input stream

let string_value = readLine(stripNewline: true)!

Reading a single number from the input stream

let numeric_value = Int(readLine(stripNewline: true)!)!

Reading a string array from the input stream

let stringArray = input.characters
                       .split {$0 == " "}
                       .map (String.init)

Reading a numeric array from the input stream

let numbericArray = input.characters
                         .split {$0 == " "}
                         .map (String.init)
                         .map {(var s) -> Int in return Int(s)!}

Reading mixed values from the input stream

let stringArray = input.characters
                       .split {$0 == " "}
                       .map (String.init)

let iValue1 = Int(stringArray[0])!
let sValue  = stringArray[1]
let iValue2 = Int(stringArray[2])!

Writing single values to the output stream

print(foo)

Writing values in string to the output stream

print ("There are \(found) or \(expected) things")

Writing array values to the output stream

print (array.map { String($0) }.joinWithSeparator(" "))

Why not use extensions, you may ask. You can do that if you like. I thought it would be better here to show the minimal elements. And generally HackerRank in very limited in its input and output aspects.

This should cover all the usual cases for input and output to enable you to use Swift with HackerRank. So, the next time you’re using HackerRank and you don’t see Swift as an option, be sure to ask the author to add it.

Read Full Post »

This is my third post on the Swift command line. In the first, I wrote on how to do command line input with Swift. In the second, I cleaned up the code after a year of tinkering with Swift. In this third installment, I get rid of more Objective-C.

Almost a month ago, Apple released Swift into the open source community. Pretty spiffy that. So, being the language wonk that I am, I bopped over to the Swift site and downloaded the sources. After a bit of scrounging, I discovered that there existed a standard library call to read a line from the input stream. I was a bit disappointed that I’d not seen this talked about anywhere, but that’s life.

So, I’ve updated my code sample and present it below. I do some forced unwrapping as the point is to highlight the process. Be sure to code defensively.

I’ll probably come back to this one more time once I’ve had a chance to look more into the Swift standard library so I can eliminate my untidy Objective-C dependent putString() routine.

//
//  swift_intput_routines.swift
//
//  Created by Charles Wilson on 9/27/2014.
//  Revised by Charles Wilson on 9/27/2015.
//  Revised by Charles Wilson on 12/21/2015.
//
//  Copyright (c) 2014 – 2015 Charles Wilson. All rights reserved.
//
//  Permission is granted to use and modify so long as attribution is made.
//

import Foundation

func putString (outputString : String = “”)
{
if !outputString.isEmpty
{
NSFileHandle.fileHandleWithStandardOutput().writeData((outputString as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
}
}

func getString (prompt : String = “”) -> String?
{
if !prompt.isEmpty
{
putString(prompt)
}

return readLine(stripNewline: true)
}

func getCharacter () -> Character
{
let inputValue     : UInt32      = UInt32(getchar())
var inputCharacter : Character

inputCharacter = Character(UnicodeScalar(inputValue))

return inputCharacter
}

func getInteger (prompt : String = “”) -> Int
{
if !prompt.isEmpty
{
putString(prompt)
}

return (getString()! as NSString).integerValue
}

func getFloat (prompt : String = “”) -> Float
{
if !prompt.isEmpty
{
putString(prompt)
}

return (getString()! as NSString).floatValue
}

Here’s the main to exercise it.

//
//  main.swift
//
//  Created by Charles Wilson on 9/27/2014.
//  Revised by Charles Wilson on 9/27/2015.
//  Revised by Charles Wilson on 12/21/2015.
//
//  Copyright (c) 2014 - 2015 Charles Wilson. All rights reserved.
//
//  Permission is granted to use and modify so long as attribution is made.
//

import Foundation

var name = getString("What is your name? ")!

if name.isEmpty
{
    name = "George"
    
    putString("That's not much of a name. I'll call you '\(name)'\n")
}
else
{
    putString("Your name is '\(name)'\n")
}

let age = getInteger("How old are you \(name)? ")

putString("You are \(age) years old\n")

// get a value without a prompt
let number = getInteger()

putString("\(number) is a nice number\n")

let floating = getFloat("Enter a floating point number: ")

putString("\(floating) works for me\n")

var c : Character

putString("Type stuff. Enter ^ when done.\n")

let sentinel : Character = Character(UnicodeScalar("^"))
var in_c     : Character

repeat
{
    in_c = getCharacter()
}
while ( in_c != sentinel )

putString("\n\n")
putString("bye\n")

Read Full Post »

Update: Apple released the Swift source. My update based on what I learned is here.

A bit over a year ago, I wrote a post about how I wanted to do command line input in Apple’s then new Swift language.

The post was pretty well received and still get a hit / week.

On the heals of finishing the WWDC 2015 session videos, I decided to start tinkering a bit more with the language. Toward this end, I’ve been re-implementing old command line games from the 1970s that were written in BASIC. This forced me to actually go back to my command line input code. Dutifully allowing XCode to update it to Swift 2 syntax, I noticed that it relied way too much on Objective C bits. I also didn’t like the way it was handling the translation from string to numeric. So, I’ve updated it.

Yes, I should just put it up on GitHub. Maybe later. For now, just cut and paste it.

//
//  swift_intput_routines.swift
//
//  Created by Charles Wilson on 9/27/2014.
//  Revised by Charles Wilson on 9/26/2015.
//
//  Copyright (c) 2014 - 2015 Charles Wilson. All rights reserved.
//
//  Permission is granted to use and modify so long as attribution is made.
//

import Foundation

func putString (outputString : String = "")
{
    if !outputString.isEmpty
    {
        NSFileHandle.fileHandleWithStandardOutput().writeData((outputString as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
    }
}

func getString (prompt : String = "") -> String
{
    if !prompt.isEmpty
    {
        putString(prompt)
    }
    
    var inputString : NSString = ""
    let data        : NSData?  = NSFileHandle.fileHandleWithStandardInput().availableData
    
    if ( data != nil )
    {
        inputString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
        inputString = inputString.substringToIndex(inputString.length - 1)
    }
    
    return String(inputString)
}

func getCharacter () -> Character
{
    let inputValue     : UInt32      = UInt32(getchar())
    var inputCharacter : Character
    
    inputCharacter = Character(UnicodeScalar(inputValue))
    
    return inputCharacter
}

func getInteger (prompt : String = "") -> Int
{
    if !prompt.isEmpty
    {
        putString(prompt)
    }
    
    return (getString() as NSString).integerValue
}

func getFloat (prompt : String = "") -> Float
{
    if !prompt.isEmpty
    {
        putString(prompt)
    }
    
    return (getString() as NSString).floatValue
}

I also update the test routine as I wasn’t checking the float bits.

//
//  main.swift
//
//  Created by Charles Wilson on 9/27/2014.
//  Revised by Charles Wilson on 9/26/2015.
//
//  Copyright (c) 2014 - 2015 Charles Wilson. All rights reserved.
//
//  Permission is granted to use and modify so long as attribution is made.
//

import Foundation

var name = getString("What is your name? ")

if name.isEmpty
{
    name = "George"
    
    putString("That's not much of a name. I'll call you '\(name)'\n")
}
else
{
    putString("Your name is '\(name)'\n")
}

let age = getInteger("How old are you \(name)? ")

putString("You are \(age) years old\n")

let number = getInteger()

putString("\(number) is a nice number\n")

let floating = getFloat("Enter a floating point number: ")

putString("\(floating) works for me\n")

var c : Character

putString("Type stuff. Enter ^ when done.\n")

let sentinel : Character = Character(UnicodeScalar("^"))
var in_c     : Character

repeat
{
    in_c = getCharacter()
}
while ( in_c != sentinel )

putString("\n\n")
putString("bye\n")

Read Full Post »

Older Posts »

%d bloggers like this: