Nick Harris

Limiting the Number of Lines in a UITextView

leave a comment »

Intro

I have a UILabel in my app that shows a maximum 4 lines of text. If the user taps on it, the view becomes editable and the user can change the text in a UITextView.

Problem

I want to limit the user to only 4 lines when they’re editing the text in the UITextView.

First Attempt – Default Behavior

By default a user can add as many lines of text as they want to a UITextView and the view will update itself to make sure the last line is visible.

This is no good for me since the user can enter more lines then I’m going to show when they’re done editing.

Second Attempt – maximumNumberOfLines

According to the docs for NSTextContainer.maximumNumberOfLines:

The layout manager uses the value of this property to determine the maximum number of lines associated with the text container. The default value of this property is 0, which indicates that there is no limit.

In Xcode 8 and iOS 10 the only effect this parameter has on a UITextView is that the last line after the max is no longer made visible. The user can keep entering text all they want but its no longer visible in the UITextView.

My Fix

The fix I came up with was to count the number of line breaks by using CharacterSet.newLines in textView:shouldChangeTextInRange:replacementText: of the UITextViewDelegate before allowing a user change.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
    let newLines = text.components(separatedBy: CharacterSet.newlines)
    let linesAfterChange = existingLines.count + newLines.count - 1

    return linesAfterChange <= textView.textContainer.maximumNumberOfLines
}

This works as intended.

But this feels like a hack around a UIKit bug.

Is it?

Written by Nick Harris

September 11, 2016 at 4:41 am

Posted in Uncategorized

Introducing Super Euchre 2.0 and Solitary Solitaire 1.0

leave a comment »

If you’ve been following along with my blog about my re-write of Euchre, my Solitaire challenge and me learning Swift and wondered if I’d ever release them to the App Store, well the wait is over!
(then some thoughts on the last couple of months)

Super Euchre 2.0

Icon 180

https://itunes.apple.com/us/app/super-euchre!/id697411524?ls=1&mt=8

– Brand New Layout and Card Faces
– New Game Replay
– Stats
– iPad Landscape and Multitasking Support
– Stats synchronization between devices

Solitary Solitaire 1.0

Icon 180

https://itunes.apple.com/us/app/solitary-solitaire/id1123243052?ls=1&mt=8

– Single or three card deal
– Auto play a winning hand
– Best time, score and moves
– iCloud syncing of games
– iCloud syncing of best time, score and moves
– Landscape support for iPhone 4S through iPad Pro
– Multitasking support on iPad

Swift

Both apps a written completely in Swift 2.2 from my standpoint. I get that the Objective-C runtime powers them but there is not one line of Objective-C in my repositories. I’ve been writing Objective-C for about half my career at this point (7 out of 15 years) and I still like the language. Its odd and quirky but I can make the devices I love do things with it so its cool by me.

Swift though… I love Swift!

Super Euchre in particular was much easier to code this time around. Higher level functions like sets, map and filter made writing the player logic much easier. I realize now that I could have accomplished the same type of approaches in ObjC using more NSPredicates but in actuality my past code was littered with tons of for loops. The Swift code to me is much easier to read and understand.

After higher level functions, my second favorite aspect of the switch to Swift is how much more I pay attention to mutability. For the player logic I decided to use NSOperations to compute some type of decision. In the past I’d have that code in one monolithic class. Using NSOperations allowed me to concentrate just on one small piece of logic making it easily testable. As far as mutability, all of my operations and even internal functions never mutate any of their input parameters. All operations have a operationResult parameter that holds the computation. No function uses the inout keyword. Even functions that do something as simple as sorting use a return value and @warn_unsed_result to remind myself that none of my functions ever mutate. I really like this approach and plan on using it in the future.

Auto Layout / Adaptive Layout

I haven’t used Xcode 8 yet but what I saw in the Platforms State of the Union at WWDC I think would have made both these games SOOOO much easier to create. If you’ve ever created landscape layouts with size classes you probably know what I mean. Interface Builder in Xcode 7 means working in a canvas that doesn’t have the same dimensions as any device you’re creating it for. Xcode 8 looks like a much better experience.

Multitasking was incredibly simple for both since I was already supporting devices from 4S up to the iPad Pro. Getting the layout right for the other devices meant multitasking was already done. I think users of such stupid time wasting card games will appreciate it!

One thing I did do different with auto layout in both of these games is to use placeholder views in the storyboards then adding all the actual views on viewWillAppear. The placeholder views give me the correct frame when the game starts (and also after rotation or switching multitasking size). What it saved me – particularly for Solitaire – was having every card in play represented on the storyboard. It made all the animations easier. Because the views that I add on viewWillAppear don’t have any auto layout constraints, I can animate their frames instead of updating their constraints (via tons of IBOutlets). I’m not sure that I’d do this very often in the future but this approach worked really well for these games.

iCloud Key / Value Storage

Both games use NSCoding and NSUbiquitousKeyValueStore to sync not only stats and best scores across devices but also unfinished games. I’m still not sold on this. It works well enough that I don’t think most people will notice how long the lag between synchronizing on one device and getting the update on another device can really be. I’m guessing in real world use, the 1 to 5 minutes won’t be noticed. We’ll see. I have a feeling this will be the biggest source of complaints and bad reviews.

App Store Preview Videos

When I first started figuring out how to do these I was so close to throwing in the towel and skipping them. I’m glad I didn’t. Once I figured out how to have an easily re-playable sequence in both games and liked what was being shown, recording and editing in iMovie for 5 different devices was pretty quick (iPhone 5, iPhone 6, iPhone 6S+, iPad, iPad Pro).

I have much more appreciation for app developers who have a preview video. I also think you get a better idea of how the app feels with a video rather then just screenshots. Will they drive more downloads? I don’t know. But now I know how to make them so that’s another skill in the toolset.

Test Flight

Loved it. Would use it again. I should note that I haven’t tried any of the newer beta distribution platforms, but Test Flight did everything I needed it to do with very little friction.

AdMob

Monetizing an app with advertising is always a little controversial. I wrote these two games to teach myself Swift, get more experience with auto layout and multitasking as well as learning the latest version of iTunes Connect which I hadn’t touched in 2.5 years. I see them more as my playground to learn and use the latest and greatest Apple technology. I don’t think I’d learn as much if I didn’t release them. Having real users is critical in learning and understanding the entire Apple ecosystem. But I want my expectations from users to be realistic. I get to learn new fun things and they get to play them at the cost of a few ads. If I want to completely redesign an app to learn something new (which I did with Super Euchre) I don’t feel the same obligation to users that I would if I were charging them. That may seem cynical and an altruistic approach of completely free apps may be more palatable for a user but I did spend 4 months working on these games. Realistically I expect to make about $100/month pre-tax on these games. I’m already practically giving them away.

I am curious though if banner ads really do underperform against interstitial ads. Euchre has a banner add while Solitaire has an interstitial ad when starting a new game. It should be interesting to see which wins.

Overall

I hope people enjoy these games. These last few months have been a lot of fun creating them, getting them to testers and polishing them off. I’ve learned a ton!

Then WWDC happened.

Now to update both code bases to Swift 3.0…

Written by Nick Harris

June 23, 2016 at 6:59 am

Posted in Uncategorized

Protocol Oriented Programming

leave a comment »

The term “Protocol Oriented Programming” has been thrown around a ton over the last year. If you’re wondering what it means, here’s an example that I dealt with tonight while working on Euchre…

Problem

Over the weekend I implemented a way to save multiple in progress games and have iCould key/value storage sync them across devices. The initial implementation was pretty dumb and saved any game in progress. This lead to a long list of saved games just in my testing. That’s not a great user experience. The user should make the decision to save their current game or delete it.

In the app the user can start a new game from the regular Game View or they can elect to resume a game which shows the Saved Games View:

Screen Shot 2016 06 06 at 11 03 37 PM     Screen Shot 2016 06 06 at 11 03 52 PM

Both of the views need to be able to prompt the user to save their current game. They both also have different actions once the user makes their decision.

Protocol Oriented Programming Solution

The best way to solve this was to first create a protocol named SaveGameProtocol that has the current GameController that I want to archive:

protocol SaveGameProtocol {

    var gameController: GameController? { get set }
}

 

Next was to add an extension to that protocol that does the save / delete prompting and handles the users decision before invoking a completion handler. This makes the extension very generic. It does its save / delete job but leaves the rest up to whatever SaveGameProtocol adhering UIViewController that wants to call it.

extension SaveGameProtocol where Self: UIViewController {

    func promptUserSaveCurrentGame(completionAction:(()->())) {

        let alertController = UIAlertController(title: NSLocalizedString("save_game_alert_title", tableName: "GamePlay", comment: ""), message: nil, preferredStyle: .Alert)

        let saveGameAction = UIAlertAction(title: NSLocalizedString("save_game_button", tableName: "GamePlay", comment: ""), style: .Default) {
            action in

            if let currentGameController = self.gameController {
                SavedGamesManager.sharedInstance.saveGame(currentGameController)
            }

            completionAction()
        }
        alertController.addAction(saveGameAction)

        let deleteGameAction = UIAlertAction(title: NSLocalizedString("delete_game_button", tableName: "GamePlay", comment: ""), style: .Destructive) {
            action in

            if let currentGameController = self.gameController {
                SavedGamesManager.sharedInstance.deleteGame(currentGameController)
            }

            completionAction()
        }
        alertController.addAction(deleteGameAction)

        presentViewController(alertController, animated: true, completion: nil)
    }
}

 

There is a trick here though. In order to present the UIAlertController using presentViewController we need to make sure the caller is a UIViewController subclass. That can be enforced by using a where clause on the extension:

extension SaveGameProtocol where Self: UIViewController

 

The last step was to set both my views to conform to the SaveGameProtocol then call the extension with whatever code each needs to continue.

Screen Shot 2016 06 06 at 11 20 34 PM     Screen Shot 2016 06 06 at 11 20 20 PM

And that’s it! Shared save game prompting code for any UIViewControllers that needs it!

Swifty!

Hat tip back to Natasha the Robot  for the pattern.

Written by Nick Harris

June 7, 2016 at 5:41 am

Posted in Uncategorized

Core Animation

leave a comment »

Core Animation is by far my favorite framework to mess around with. Its been my favorite since I started writing Euchre way back for iPhoneOS 2.1. Its simple to use and can be incredibly powerful in calling attention to UI elements when they change. Its also very easy to over do it with animations. I liken it to salt and pepper in cooking. You can enhance your app with just a pinch but too much and it ruins everything else you’re trying to do.

I’ve been playing around with how to show trick winners and hand winners in Euchre for the umpteenth time over the last two evenings. Its one of the parts of continuously re-creating a Euchre game for iOS that I really love. This effort is especially meaningful after getting a grip on how to represent the game in AutoLayout.

I overdid my animations in Super Euchre (the version available in the App Store) particularly around when a team wins a trick or a hand. The state of the game was over represented on the view and the animations to those changes were jarring. With my new take on Euchre I cut those down substantially while still doing subtle things to draw attention:

 

I like it but I’d be interested in hearing thoughts*.

PS:
I had a blast with animations on Solitaire. Dragging piles was a little challenging but fun.

 

*I don’t present myself as a designer. I’m just a developer who wants to tinker with the design of my own apps that make little money.

Written by Nick Harris

May 11, 2016 at 5:31 am

Posted in Uncategorized

Top Toolbar Design

leave a comment »

I saw this screenshot from the Starbucks app tonight. I was curious (I’m not a Starbucks guy) so I downloaded the app myself.

Screen Shot 2016 05 05 at 10 29 57 PM

Personally I like the design a lot. But what really caught my eye is the use of a top of view toolbar instead of a bottom tab bar.

For my Solitaire experiment I decided to go with the same top toolbar approach. When I went back to working on Euchre I made the same decision.

Screen Shot 2016 05 05 at 10 30 23 PM     Screen Shot 2016 05 05 at 10 31 43 PM

The biggest reason for me was the perception of persistence that tab bar views have. Each tab feels like something that’s always active in the app. For my dumb card games, things like rules or best scores don’t need to feel like they persist. You can bring them up when you’re interested but can then dismiss them and feel like they’re “gone”. Using animations can enhance that feeling for the user instead of the flat feeling of switching between tabs. Presenting modal views on top of your base view feels more interactive to me then tabs.

I’ve also accidentally tapped another tab when holding my phone and jumping me from what I was trying to do. Having the navigation buttons further away from my “work area” means I need to make a more definitive action to switch my working context.

The Starbucks app seems to do exactly what I’ve been attempting to do with my horrible design skills. Views appear from the bottom and overlay the base view while leaving the menu visible. Swipe gestures can be used to dismiss them instead of reaching all the way for the top toolbar. Its not a difficult effect to do and I really like the feel of the app more then I would if they had used a tab bar. There are some things they could do to tighten down the animation (adjusting the background image after viewDidAppear is rather jarring) but all in all I do like this approach to app navigation.

Are there other apps taking this approach?

Written by Nick Harris

May 6, 2016 at 4:48 am

Posted in Uncategorized

PDF Playing Card Assets

leave a comment »

Xcode gave us the ability to use PDF (or single vector driven graphics) a while ago and I’ve never heard good or bad if they should be used instead of strict sized based PNG assets.

I’ve been playing around with them though with Euchre and Solitaire and I like how my PDF assets look on all my devices.

There was a sizable resistance against PDF assets a few years ago. Is that still the case?

Here are some screen shots of my PDF cards on a 4s, 5, 6, 6SPlus, iPad Air and iPad Pro…

4S

IPhone4s

5 (or SE)

IPhone5

6

IPhone6

6S Plus

IPhone6SPlus

iPad Air 2

IPadAir2

iPad Pro

IPadPro

 

Those blog images are probably hard to judge from.

Here is my Sketch file and PDF assets I made.

Feel free to use them in your own apps.

But back to the original question…

Are PDF assets OK now?

Written by Nick Harris

March 23, 2016 at 7:16 am

Posted in Uncategorized

Selectors With Parameters in Swift 2.2

with 16 comments

I went back today and recompiled all my latest Swift projects  – Euchre, CloudKitPOC, Suntracker, Solitaire – to see how much Swift 2.2 would break them. The only thing that I got warnings about (I’m a 0 warnings dev) was about changing from string selectors to using the #selector() syntax. They were all warnings but I had problems fixing one of them. The “Fix-it” solution ended up being another warning.

In Solitaire I have a GameController and a GameViewController. The GameViewController is strictly UI only. There is no game logic what-so-ever in it. All of that is contained in the GameController. I also created a PlayingCardImageView subclass of UIImageView to handle all the interaction with the playing cards. For instance, tapping a playing card will execute any plays that card can make in the game.

When implementing this, I had to decide if I wanted pass the GameController into every PlayingCardImageView or have the target and selector of the UITapGestureRecognizer refer back to the GameViewController. I opted for the later. I only wanted one class to be responsible for passing user interactions back to the GameController.

My code in the PlayingCardImageView for 2.1 was:

let tapGestureRecognizer = UITapGestureRecognizer(target: gameViewController, action: "cardTapped:")
self.addGestureRecognizer(tapGestureRecognizer)
 

The “Fix-it” solution:

Screen Shot 2016 03 22 at 9 07 33 PM

which then lead to…

Screen Shot 2016 03 22 at 9 12 24 PM

Hopefully the first thing you’re thinking as a seasoned Xcode user is “Never use Fix-it!!” and you’d be right. Unless you understand what Fix-it is actually doing its much better to dig into the problem yourself and figure out what the fix should be.

The proper solution in Swift 2.2 for this is:

let tapGestureRecognizer = 
UITapGestureRecognizer(target: gameViewController, action: #selector(gameViewController.cardTapped(_:)))
self.addGestureRecognizer(tapGestureRecognizer)
 

It wasn’t the most obvious syntax to arrive at but at least I know now.

BTW – here’s a great rundown of Swift 2.2 changes. I’m looking forward to trying out tuple comparisons – particularly with my NSOperation operationResult tuples in unit tests.

Update

I want to point out that I figured it out quite easily with Xcode code completion. I don’t want this post to sound like a dump on the Xcode team. Xcode gets better and better with every release! I bet its just a miss in the Fix-it logic.

Screen Shot 2016 03 22 at 10 03 02 PM 

Written by Nick Harris

March 23, 2016 at 3:37 am

Posted in Uncategorized