Thursday, June 19, 2014

Advanced Swift - Part 1

This is a summary of the topics and notes that I found interesting from watching the Advanced Swift WWDC session 404 by John McCall and Dave Abrahams.  I highly recommend you watch the session.  It also has some commentary from me which you may or may not agree with.  Please feel free to join the conversation. :)

I have also attached a swift playground file with the sample code.


The Simple Thing Class


The first class the session introduced was the "Thing" class.  It's fairly basic, so I went ahead and completed its implementation. This was also the first time I realized that class initializes don't use the "func" keyword!  This is because initializers have some special characteristics that distinguish them from functions some of which is explored later on.


The location can be nil (no object) so it uses the "?" modifier.  We can easily create an instance of "Thing" using named parameters:


The simple Thing class is actually using a simplified version of argument names that make the caller's argument name equal to the name used by the initializer.  You can also create a version that uses the full argument names.

Full Argument Names


You can actually use the argument definitions full form to define argument names that allow the caller of the initializer to use a different name then what the initializer itself uses.


You can also do a condensed version of the arguments where the caller doesn't need to specify the argument name.  This is done through an anonymous wildcard expression.  Let's first take a look at these expressions to see how they work and then we will apply them to argument definitions.

Anonymous Wildcard Expressions (_)


Swift has the concept of an anonymous wildcard expression which is represented by an underscore (_). The wildcard expression can be used when you want to explicitly ignore a value during assignment. This comes in really handy when dealing with tuples.


You can apply the same technique to argument names.

Anonymous Argument Names


Instead of having explicit argument names you can specify anonymous argument names.  This should only be done in situations where the code becomes more readable/maintainable without the named parameters.


To me this is an example where Swift is giving too much flexibility in its expressiveness and is asking for abuse.

Protocols


Protocols are like Objective-C protocols in that they don't provide an implementation.   Here is an example:


This example also introduced the difference between the === and the == operator.  The === means the objects must be the same instance where == just means they need to be equal but not necessarily the same instance.

Testing for Protocol Conformance


You can use a conditional cast to check if an object conforms to the protocol.  However, the example given in the session was incorrect.  When trying to compile it, I kept getting an error "cannot downcast from 'Thing' to non-@objc protocol type 'Pullable'".  According to the documentation under "Checking for Protocol Conformance” you can only test for protocol conformance of objective-c compatible protocols.   This makes the protocol only usable for class types which is fine in this case.  So making the adjustments to the protocol we can now implement a function that tests for conformance.


The example given also only specified the use of the "as" operator as opposed to "as?".  However, the documentation states that "as" will trigger a runtime error if it can't cast to the specified type so we need to use the "as?" operator to allow for cases when the object doesn't conform to the protocol.  So we had to use the "as?" operator as shown above.

Wrap Up


Lots of people are starting to learn Swift, including myself, so I hope this was helpful.  If you see anything incorrect or if you have different opinions please share your thoughts.

You can download the playground file which will allow you to play with and copy and paste all the code used.  Note that you will need XCode 6 to run the example.

Thanks,
Tod Cunningham
Five Lakes Studio, LLC
co-founder

Monday, July 1, 2013

Newsletter

We have had more then 700,000 downloads of our apps since 2010, and we don't have any way to contact those people or know who they are outside of our apps.  For in-app engagement I highly recommend the Apps Fire Booster SDK which I did a blog post about awhile ago.  However, I think we need to be doing more to stay in touch with our users.  I talked with Jody Burgess who runs a strategic marketing company and she planted a bug in my ear about collecting e-mail addresses.

Newsletter Signup


I decided that collecting e-mail addresses would be a good idea, but I wanted to make sure we are adding value for that e-mail address and that we don't spam our users.  Ken and I decided to add a newsletter signup to Picross HD.

We added a simple signup process that will prompt users to signup for the Newsletter.  The signup offer will be shown after several launches of the App or upon request.


We are using a double opt in process that requires the user to ask to signup for the newsletter as shown above and via a confirmation e-mail.

Mailchimp


We are using mailchimp.com to manage the e-mail lists for us.  This helps us stay in compliance with different e-mail laws and manages all the opt-in and out stuff.  They also have a simple little api called ChimpKit on git hub.  I wish they had done a bit more work on it as it's just a very thin wrapper around their rest api, but it is still useful.

They also support localized e-mails, but I have had a hard time getting that setup correctly.  For this first pass, I'm just going to go in english, but I would like to support japanese better in the future as about half the Picross HD user base is japanese.

At the time of this writing, we haven't gone live with Mailchimp so I don't know how well they are going to perform until we get a few e-mail campaigns under our belt.

Privacy Policy


The one thing mailchimp doesn't really help with is in the creation of a Privacy Policy.  If you are collecting names and e-mail addresses you will need a privacy policy.  It cost about $650 to have one created along with a Terms of Use for our website and an End User License Agreement.

Free Puzzles


The main use of the newsletter will be to feature new free puzzles that can be played either via paper or via our games.  Here is an example of what the newsletter will look like:


We keep the e-mail really simple so that it has the best chance of being opened by various e-mail readers, but when you click on one of the puzzles it will open the puzzle in our puzzle view.

Puzzle Viewer


The puzzle view is interesting because it uses Javascript to give the user more options.  For example, if you have it open on an iOS device it will give you the option of installing Picross HD or if you have Picross HD already installed it will give you the option to play the puzzle directly in Picross HD.

If you are viewing it on a computer it gives you the option of download Picross HD through iTunes or print the puzzle.  You can even show the puzzle's solution so it's possible to play the puzzle with pen and paper.  We hope users will play it in Picross HD, but we want people to share our puzzles with their friends and have no barriers to playing our puzzles.


It was a little tricky to get it to work, just contact me if you would like me to share the Javascript code with you or you can view the page source to see it yourself.

The nice thing about the Puzzle view is we will also be able to do some social campaigns on Facebook and Twitter.  I plan on posting free puzzles to Facebook and Twitter which will bring people to the Puzzle viewer.  They will hopefully enjoy the puzzle and choose to signup for the newsletter or download Picross HD.

Cross Promote


In addition to Picross puzzles, we plan on making Hashi puzzles available through the newsletter.  We think people who like Picross puzzles will also probably like Hashi puzzles and this is a way to introduce them to Hashi puzzles and our Hashi app.

We will also use the newsletter to talk about upcoming releases and news we think our users may be interested in hearing about.

Conclusion


It's kind of amazing all the possibilities that open up just by having interested user's e-mails.  I'm excited to see how this goes over with our users and through our planned social campaigns.

Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your app marketing experiences.  Also, feel free to signup now for our newsletter.  It may still be in a beta form, and it won't be able to open puzzles in Picross HD until the 3.4 version is available.  Other then that it should work fine.  :)


Thanks for reading and be sure to visit us at Five Lakes Studio.



Monday, April 8, 2013

iOS In-App Purchases

This is hopefully a concise getting started with in-app purchases article. Five Lakes Studio has had a fair amount of success with leveraging in-app purchases, and I wanted to share some of the lessons we have learned along the way and also share some code to help make basic in-app purchases a little easier.  This article focuses on non-consumable purchases with built-in product (app) delivery.

Setting Up Your Account


In order to use in-app purchases you have to complete several steps.  A good guide to how to do this is  TN2259 Adding In-App Purchase to your iOS and Mac Applications.   I would recommend taking some time and reading it thoroughly.

One of the key things you need to do is make sure your app has a specific AppId such com.appleseedinc.MyGreatApp.   If your current AppId is using wildcards (".*") you will need to replace it with a fixed AppId and regenerate and reapply the provisioning profiles.  This is because in-app purchases can't be shared across multiple apps.

Creating Test Accounts


You will also need a test account.  These can be created using your iTunes Connect account.




In order to test with the test account, you will need to logout of your current iTunes AppStore account.  You can do that in the "Settings" app under "iTunes & App Stores".


However, don't try to login with the test account through the Settings app.  The test account is only valid in the sandbox environment.  In order to use it, you enter it from within you app when you initiate the in-app purchase.  It will then ask you to login and then you can use the test account you just created.  Once you do this, you can logout of the test account through the Settings app.

Setting up In-App Purchases


You setup the items you want to be purchasable via iTunesConnect.  


This includes picking the type of in-app purchase, it's product id used to reference the purchase from within you app, pricing, and finally the actual text displayed to the user during the purchase process.

This article focuses on Non-consumable In-App Purchases.  These type of purchases only need to be purchased once by users. They do not expire or decrease with use and they can be restored.

Purchasable items need to be approved by apple, and they must include a screenshot.  When you define a new release of an app you can pick which new in-app purchases are available in the app.

It's App Time


Now it's time to start doing work in the app.  At this point, you should have your AppId provision profile set, a test account setup, and one or more non-consumable purchases configured in the App Store through iTunesConnect.  The StoreKit is used to communicate between your app and the AppStore.


The simplest type of in-app workflow to implement is for built in product delivery.  The workflow looks like:


The other workflow is a server based authentication workflow which is significantly more complicated and isn't a focus for this article.

I have made available a class called FLOStoreManager that helps manage the built in product deliver workflow and is part of the Five Lakes Studio Open Library project on GitHub.

FLSOpenLibrary


I'm happy to make FLOStoreManager available under the MIT license as part of the Five Lakes Studio Open Library on GitHub.  The FLOStoreManager class does most of the work to manage the in-app purchase process.   I suggest you download it and at least use it as an example.  

NOTE: The FLOStoreManager makes reference to featureId which is equivalent to to the App Store productIdentifier.

There are 3 main parts to the in product delivery process: Download, Present, and Purchase.

Downloading Purchasing Information


The in-app product definitions are stored on the App Store and must be download to the app before presenting or trying to purchase the item.  This is a download of the product information or meta-data such as product price.   Apple enforces this through the App review process so don't try to skip this step even if you think you can just embed all the meta-data in the app.  Apple still requires your to download and honor this information as it exists in iTunesConnect.

The product definitions contain information such as product description and price. In order to fetch the product definitions, the app needs to know the product ids in advance.  There is no method to query the product ids from the App Store.  This means the App needs to know the product ids by either hard coding them or by other means such as downloading them from a server.

The SKProductsRequest class is used to fetch the product definitions for a set of feature id's.  The FLOStoreManager wraps this in a handy method called startAsyncFetchOfProductForFeatureList.

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSSet *featureSet  = [[NSSet alloc] initWithArray:@[@"ProductId1", @"ProductId2"]];
    [[FLOStoreManager defaultManager] startAsyncFetchOfProductForFeatureList:featureSet];
}

This implementation also does some handy work for you automatically:
  • Auto retry on failed attempts
  • Sends an NSNotification (kFeatureListReady) when the feature list has been successfully retrieved.
  • If the feature list has already been retrieved and matches the given feature then it will only try and update the list once a day.   This is handy since it is called in applicationDidBecomeActive which may get called multiple times as users enter and leave the app.
  • Keeps track of the "registered" features and the product information associated with them
I usually request the product information during applicationDidBecomeActive so it will be downloaded and available as soon as is possible so the purchasable items can be presented to users.

    Present Purchasable Items


    It's up to you to decide how to present the in-app purchases to your users.  However, the App Store uses UIAlert messages which you can not control other then through some text customization.  These customizations are done through iTunesConnect when defining the in-app purchase.

    Picross HD - Daily Puzzle Pack In-App Purchase
    You also shouldn't present purchases for items whose purchasing information hasn't been downloaded.  Apple can reject your app if you try to do that.

    One of the things you are going to want to know from the server is the price of the item.  This can vary based on the country and also can be changed in iTunesConnect.  FLOStoreManager has a handy routine to allow you to retrieve the localized price of the product formatted in a nice string.

    NSString *price = [[FLOStoreManager defaultManager] formattedPriceForFeatureId:@"ProductId1"];
    

    You will also want to take into account some other factors in the UI such as:
    • The act of purchasing an item is done asynchronously so you will probably want something to indicate when a purchasing is in progress,
    • You will need to handle the notifications when the purchase either completed or failed. 

    Purchase


    The SKPaymentQueue is used to initiate a purchase.   It's easy to initiate a purchase, but it does require some tricky handling of the payment queue.  FLOStoreManager tries to make this really easy.  You just call startAsyncPurchaseOfFeature to begin the purchase:

    [[FLOStoreManager defaultManager] startAsyncPurchaseOfFeature:@"ProductId1"];
    

    Once the request is completed, one of two NSNotifications will be sent:
    • kFeaturePurchased is sent if the purchase is successful. The notification object with be the featureId NSString
    • kFeaturePurchasedFailed is sent if the purchase failed.  The notification object with be the featureId NSString
    FLOStoreManager also keeps track of which product ids (features) are in the process of being purchased.  This is handy when updating or displaying a view and you need to know if something is being purchased.


    if( [[FLOStoreManager defaultManager] isFeatureBeingPurchased:@"ProductId1"] )
    {
        // The feature is in the process of being purchased
    }
    
    if( [[FLOStoreManager defaultManager] isAnyFeatureBeingPurchased] )
    {
        // Some feature is being purchased, we don't care which one
    }
    

    One of the limitations with FLOStoreManager is that it doesn't try to do purchase receipt validation. There is a vulnerability in iOS 5.1 and earlier related to in-app receipt validation.   It is not a simple topic to validate a receipt.  Apple has a handy article that talks through the "In-App Purchase Receipt Validation on iOS".  If people are willing to go through the hassle to hack my app to save a buck or two then so be it, I don't think they would be willing to pay for it anyway.  Perhaps some day they will change there ways.

    You will also need to handle the condition of a purchase request that gets completed after the user has left your app.  In order to handle this case, one of the first things the app should do is setup the  SKPaymentQueue in application:didFinishLaunchingWithOptions by adding an observer.  This needs to be done so the app can receive payment notifications from the AppStore.  This is all taken care of by FLOStoreManager just by getting the defaultManager.

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [FLOStoreManager defaultManager];  // Allows us to receive AppStore notification
    }
    

    Once the user starts purchasing items, how do you track what has been purchased?

    Purchase Tracking


    It is up to the app to figure out how to store and keep track of purchased items.  The StoreKit does provide a method called restoreCompletedTransactions which is available as part of SKPaymentQueue  to restore non-consumable purchases.  However, it requires that the user provide their authentication to the Apple Store.  So it's usually called in response to an explicit action by the user to restore purchases.

    FLOStoreManager exposes the ability to restore purchases through its own restoreCompletedTransactions method.  Using  FLOStoreManager also has the added benefit of sending kFeaturePurchased notifications for items that where purchased and needed to be restored.  It will also send a kPurchaseRestoredCompleted notification after all items have been restored.

    The other big advantage of FLOStoreManager is it has a built in mechanism to keep track of non-consumable purchases.  It uses the built-in keychain to keep track of purchases.  The nice thing about the keychain is that it persists across deletes of the app.  You can also instantly query FLOStoreManager to see what has been purchased.

    if( [[FLOStoreManager defaultManager] isPurchased:@"ProductId1"] )
    {
        // The feature has been purchased
    }
    

    Conclusion


    Wow you made it this far.  This turned out to be a wee bit longer then expected, but I hope you found it useful.

    Please feel free to contribute to the FLS Open Library.  I wasn't planning on making this open source so it wasn't designed to be general use, but I think it provides a good start and example.  It also contains a lot more functionality then discussed here including an extension to handle consumable purchases.

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your in-app purchase experiences.

    Thanks for reading and be sure to visit us at Five Lakes Studio.

    References


    https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git
    TN2259 Adding In-App Purchase to your iOS and Mac Applications
    In-App Purchase Programming Guide
    In-App Purchase Receipt Validation on iOS
    iPhone Tutorial – In-App Purchases By Mugunth Kumar


    Sunday, April 7, 2013

    Quick Tip: How to show source code in the blog

    I have been trying different solutions for showing source code in my blog.  This has been a little harder by the fact I'm trying to show Objective-C.  I have finally found just the trick. It's http://hilite.me/ by Alexander Kojevnikov.  It has a very simple copy/paste interface that just works.  You can also do some customizations and pick between may different styles.

    Using it is as simple as:
    1. Paste your source code
    2. Hit Highlight
    3. Copy and paste the HTML


    You can also customize the embedded css style information and pick the language.  I added a font size style to the css "font-size:small;" and here is what it looks like:

    - (void)alertViewCancel:(UIAlertView *)alertView
    {
        if( m_alertBlock != nil )
        {        
            m_alertBlock( kAlertViewCanceled );
            m_alertBlock = nil;        
        }    
    }
    

    The nice thing about this solution is that everything needed is embedded in the HTML block so there is no setup required on the blog itself.

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear if this was useful and what you do to show source code on the web.

    Thanks for reading and be sure to visit us at Five Lakes Studio.

    Wednesday, March 13, 2013

    Cocoa Debugging Tip


    I'm attending my local Ann Arbor CocoaHeads meeting tomorrow, and the topic is
    Objective Tips.  So I thought I would share a tip.

    What do you do when you get a crash due to an uncaught exception such as:

    2013-03-13 13:30:10.186 Picross[43233:1303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AppDelegate crash]: unrecognized selector sent to instance 0xc04de10'*** First throw call stack:
    (0x355b012 0x32ffe7e 0x35e64bd 0x354abbc 0x354a94e 0x3313663 0x12f54 0x3f0153f 0x3f13014 0x3f042e8 0x3f04450 0x926b5e12 0x9269dcca)
    libc++abi.dylib: terminate called throwing an exception

    This can get really frustrating as you need to figure out where in your code it crashed.  Debugger to the rescue.  In the call stack, you can find the first "low" value.  This usually represents your code.  Then you just do a symbol lookup on that value.  Such as the following when using LLDB.
    im loo -a 0x12f54
     This does a image lookup which gives a nice dump including the file and line number of the offending code:

    Address: Picross[0x00012f54] (Picross.__TEXT.__text + 67540)
    Summary: Picross`__57-[AppDelegate application:didFinishLaunchingWithOptions:]_block_invoke112 + 52 at AppDelegate.m:216

    You can see from this dump that the offending code was at line 216 in the AppDelegate.m and was from a block where I was calling a selector that didn't exist.


    I also find this GDB to LLDB guide to be a handy reference of the commands available in LLDB.

    I hope this short quick tip was helpful.  Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your experiences with the debugger or any tips you might have.


    Monday, October 22, 2012

    GameCenter Turn Based Matches


    We have been looking and doing a major overall to Euchre HD.  In particular, we are looking at
    leveraging GameCenter's turn based games.  Right now we use basic Game Center matchs, but there lots of good benefits with being able to leverage the turn based capabilities.  The two big benefits we want are:

    • Support for "live" and "non-live" matches (turn based)
    • Support for Timeouts
    • Improved Game Center match UI

    A really good example to get started with Game Center Turn Based match's is Beginning Turn-Based Gaming with iOS 5 by Jacob Gundersen.  Some API's have been changed in iOS 6, but it is still a really good tutorial.

    This was my first real experience working with the Turn Based API, and I wish I would have know the following going into the project.

    Passing Turn To Yourself

    It turns out that a match participant may "pass" the turn (baton) to themselves.  I had assumed that wouldn't be allowed, but it turns out the API does allow it, and it definitely simplified some of my game play logic.

    The only catch is that other players won't be notified of the changes to the Game State when you pass the game baton to yourself.

    Participant Timeout (new in iOS 6)

    I thought that when a player timed out their participant matchOutcome would get set to GKTurnBasedMatchOutcomeTimeExpired.  However, it turns out you have to determine this condition yourself and set the appropriate matchOutcome for the participant.

    Another interesting case is when a participant is in a matching state.  The timeout isn't applied against that unmatched participant.

    Changes to Authentication

    iOS 6 depreciated the old authenticateWithCompletionHandler and replaced it with GKLocalPlayer.localPlayer.authenticateHandler. They changed the block callback a bit, but other then that it looked equivalent. However, the authenticateHandler in iOS 6 won't present the login view if the user cancels it. I realize game center will auto lockout an app after 3 cancel attempts, but I'm talking about just 2 attempts. If they cancel the login, they have to leave the app and come back before Game Center will present the login even through the authenticateHandler is getting set again. I was able to workaround the issue by continuing to use the depreciated authenticateWithCompletionHandler.

    The reason this is important for Euchre HD is that it requires Game Center for multi-player. The app tries to authenticate to game center on launch, but if the user cancels we don't ask them at launch again so they won't get nagged. What we do is show a Game Center Login button if they aren't logged in when they select multi-player.

    Number of Players in a Match (Updated 11/1/2012)

    One problem we have found is that if you have a variable number of players and then start a match with "auto-match", Game Center will start the match with the "minimum" number of players.  It does this even if the Game Center match-making UI is showing auto-match spaces for more then the minimum number of players.

    Let me try and explain this a bit better. One thing we do in Euchre HD is to allow people to pick the number of human players they want in a match.  They can pick from 2 to 4 humans.  Euchre is of course a 4 person game, but we fill in the remaining spots with computer players.

    Game Center provides a really nice interface for forming a multi-player game.  Here is an example, that shows a 2-4 player game.


    The play can add or remove players players as long as they stay within the defined min/max limits.


    However, if the player selects "Play Now" and "Auto-match" is selected a match will only be formed with the minimum number of players.  In the above example, even through 3 players are being shown as Auto-match, Game Center will only start a 2 player match.

    Here is the example code showing how the request is created.

        GKMatchRequest *request = [[GKMatchRequest alloc] init];
        request.minPlayers = 2;   
        request.maxPlayers = 4;
        request.playersToInvite = playersToInvite;
        request.playerGroup = 0;
        request.defaultNumberOfPlayers = 4;
    As anyone else encounter this issues?  Any good suggestions on how to handle it?  I would rather not write my own custom matchmaking interface.


    Conclusion

    Overall, turn based Game Center is a huge help in building multi-player games.  I was still surprised about how many special cases have to be handled and how much testing is needed.  I guess multi-player is just hard.  :)

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your experiences Game Center.  I hope this was helpful.

    Thanks for reading and be sure to visit us at Five Lakes Studio.







    Friday, August 31, 2012

    NSMutableArray Weak References


    I had the need to store non-retained objects to prevent a retain lock loop.  I found a couple of different ways to do this.  I started by trying to implement a derived version of NSMutableArray.  There is a nice example by Mike Ash on how to do implement a NSMutableArray.  It would be fairly easy to modify his example to remove the retain/release pieces.  However, I was a bit nervous when it came to testing the code and my changes.  While he has a test in place, the test wouldn't work if the objects weren't retained.

    So I kept looking and found a great example on Stack Overflow by Mark Powell that takes advantage of Core Foundation's Mutable array.


    I haven't done much with Core Foundation services, but I have to say that it's amazing how easy this was to do.  I modified the example above to work with ARC so there is a __bridge cast for the returned CGArrayCreateMutable. I put this along with my changes in a small class and header file which can be downloaded at Download NSArrayWeakReference Source.

    I hope you found this helpful.

    - Tod