tag:blogger.com,1999:blog-80611576264033556832024-03-05T22:22:17.786-08:00Five Lakes StudioDevelopment BlogTodhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.comBlogger30125tag:blogger.com,1999:blog-8061157626403355683.post-29637799700406761812016-06-30T09:55:00.000-07:002016-06-30T09:55:02.123-07:00Swift 3 - Selection Sort ChallengeErica Sadun has an interesting post on the <a href="http://ericasadun.com/2016/06/28/make-it-swifter-challenge/">Make it Swifter Challenge</a> for a functional implementation of a selection sort. The original challenge was <a href="https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160627/002371.html">posted by Adriano Ferreira</a> on the Swift Users email list.<br />
<br />
While the selection sort doesn't scale well with O(n^2), it does do well at performing in tight memory constraints. It's also very easy to implement. However, most of the solutions submitted ended up doing a lot of memory/array copying.<br />
<br />
Here is my attempt at solving the problem in functional way with minimal memory allocation / array copying. Note this does request Swift-3:<br />
<br />
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">func selectionSort(_ array: inout [Int]) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> for index in 0..<array.count {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> let minIndex = array</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .indices</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .clamped(to: index..<array.count)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .min(isOrderedBefore: { array[$0] < array[$1] })</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if index != minIndex {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> swap(&array[index], &array[minIndex!])</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
</div>
<br />
Here is a non-mutating version of the above:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">func selectionSorted(_ originalArray: [Int]) -> [Int] {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> var array = originalArray</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> for index in 0..<array.count {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> let minIndex = array</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .indices</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .clamped(to: index..<array.count)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .min(isOrderedBefore: { array[$0] < array[$1] })</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if index != minIndex {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> swap(&array[index], &array[minIndex!])</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> return array</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
As an extension to Array:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">extension Array {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> func selectionSorted(isOrderedBefore: (Element, Element) -> Bool) -> [Element] {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> var arrayCopy = self</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> for index in 0..<arrayCopy.count {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> let minIndex = arrayCopy</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .indices</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .clamped(to: index..<arrayCopy.count)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> .min(isOrderedBefore: { </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> isOrderedBefore(arrayCopy[$0], arrayCopy[$1]) } )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> if index != minIndex {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> swap(&arrayCopy[index], &arrayCopy[minIndex!])</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> return arrayCopy</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
Example:<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">let x = [1, 3, 5, 2, 4, 9, 8, -5, 6, 4]</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">let minSort = x.selectionSorted(isOrderedBefore: { $0 < $1 })</span><br />
<br />
<br />
<div>
That was my stab at making a functional version of SelectionSorted. Please feel to leave your comments below.</div>
<div>
<br /></div>
<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0tag:blogger.com,1999:blog-8061157626403355683.post-26929244202514161722015-11-02T13:28:00.000-08:002015-11-03T17:14:01.421-08:00Swift NSTimer and Blocks (Closures)<h2>
Introduction</h2>
<br />
I'm always a bit surprised to discover that NSTimer doesn't have support, out of the box, for blocks or closures. So I decided to put together this simple extension to NSTimer that supports swift closures.<br />
<h2>
</h2>
<h2>
The NSTimer Classic Way</h2>
<br />
NSTimer has been around for a long time. It uses the objective-c runtime to invoke some code after a period of time. The invocation can be done by either an objective-c <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/#//apple_ref/occ/clm/NSTimer/scheduledTimerWithTimeInterval:invocation:repeats:">NSInvocation</a> object or via <a href="https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html">selectors</a>. Let's look at a simple example of invoking a selector in swift using a NSTimer.<br />
<br />
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1">class</span><span class="s2"> SimpleTimerTest</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">var</span><span class="s2"> timer : </span><span class="s3">NSTimer</span><span class="s2">?</span></span></div>
<div class="p2">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">func</span><span class="s2"> someTask( timeout:</span><span class="s3">NSTimeInterval</span><span class="s2"> )</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {</span></span></div>
<div class="p3">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s1">self</span><span class="s4">.</span><span class="s2">timer</span><span class="s4"> = </span><span class="s3">NSTimer</span><span class="s4">.</span><span class="s2">scheduledTimerWithTimeInterval</span><span class="s4">( timeout,</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> target:</span><span class="s1">self</span><span class="s2">,</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> selector:</span><span class="s5">"timerCallback:"</span><span class="s2">,</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> userInfo:</span><span class="s1">nil</span><span class="s2">,</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> repeats:</span><span class="s1">false</span><span class="s2"> )</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p2">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">@objc</span><span class="s2"> </span><span class="s1">func</span><span class="s2"> timerCallback( timer:</span><span class="s3">NSTimer</span><span class="s2"> ) {</span></span></div>
<div class="p4">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s6">FLLog</span><span class="s4">.</span><span class="s6">info</span><span class="s4">( </span><span class="s2">"*** Timer Fired ***"</span><span class="s4"> )</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
<br />
It's fairly easy to invoke the selector. One important detail is that the method invoked must be defined with <span class="s1" style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@objc</span>. This allows the objective-c runtime access to the method. However, there is no compile time check for this, if you forget the <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@objc</span> modifier then you will get an "Unrecognized selector" runtime error when the selector is invoked.<br />
<br />
There is also no spell checking for the selector in swift so if you mess up the selector string you will also get a runtime error. Objective-c has a <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@selector</span> compiler directive which will validate the selector exists at compile time, but there is no equivalent to this in swift.<br />
<br />
Another point to consider with this approach is that the target instance of the selector will be retained by the timer. This means for the above example that SimpleTimerTest will be retained until the timer is done with it.<br />
<br />
These basic tools can be used to implement our own extension to NSTimer that allows a block to be invoked when the timer fires.<br />
<br />
<h2>
NSTimer Block</h2>
<br />
A simple NSTimer extension can be created that allows blocks or closures to be used. Here is an implementation that does this:<br />
<br />
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1">public</span><span class="s2"> </span><span class="s1">typealias</span><span class="s2"> FLTimerBlock = (timeinterval:</span><span class="s3">NSTimeInterval</span><span class="s2">) -> </span><span class="s3">Void</span></span></div>
<div class="p1">
<span class="s3"><br /></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1">extension</span><span class="s2"> </span><span class="s3">NSTimer</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">private</span><span class="s1"> </span><span class="s4">class</span><span class="s1"> TimerBlockContainer {</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">private(set)</span><span class="s1"> </span><span class="s4">var</span><span class="s1"> timerBlock:</span><span class="s3">FLTimerBlock</span></span></div>
<div class="p3">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">init</span><span class="s1">( timerBlock:</span><span class="s3">FLTimerBlock</span><span class="s1"> ) {</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">self</span><span class="s1">.</span><span class="s5">timerBlock</span><span class="s1"> = timerBlock;</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p3">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">public</span><span class="s1"> </span><span class="s4">class</span><span class="s1"> </span><span class="s4">func</span><span class="s1"> scheduledTimerWithTimeInterval(timeInterval:</span><span class="s3">NSTimeInterval</span><span class="s1">,</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> repeats:</span><span class="s3">Bool</span><span class="s1"> = </span><span class="s4">false</span><span class="s1">,</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> block:</span><span class="s3">FLTimerBlock</span><span class="s1">) -> </span><span class="s3">NSTimer</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {</span></div>
<div class="p4">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s4">return</span><span class="s2"> </span><span class="s4">self</span><span class="s2">.</span><span class="s1">scheduledTimerWithTimeInterval</span><span class="s2">(timeInterval,</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> target: </span><span class="s4">self</span><span class="s1">,</span></span></div>
<div class="p5">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> selector:</span><span class="s1">"_executeBlockFromTimer:"</span><span class="s2">,</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> userInfo:</span><span class="s3">TimerBlockContainer</span><span class="s1">(timerBlock:block),</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> repeats:repeats)</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p3">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">@objc</span><span class="s1"> </span><span class="s4">class</span><span class="s1"> </span><span class="s4">func</span><span class="s1"> _executeBlockFromTimer( timer:</span><span class="s3">NSTimer</span><span class="s1"> ) {</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">if</span><span class="s1"> </span><span class="s4">let</span><span class="s1"> timerBlockContainer = timer.</span><span class="s5">userInfo</span><span class="s1"> </span><span class="s4">as</span><span class="s1">? </span><span class="s3">TimerBlockContainer</span><span class="s1"> {</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> timerBlockContainer.</span><span class="s5">timerBlock</span><span class="s1">(timeinterval:timer.</span><span class="s5">timeInterval</span><span class="s1">)</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p2">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></span></div>
<br />
The timer extension does a couple of nice things:<br />
<ol>
<li>The @objc time method is contained in the extension</li>
<li>No selector spelling mistakes outside the extension</li>
<li>The NSTimer will retain the contained TimerBlockContainer as opposed to the class using the NSTimer. If the block needs to retain references, it will do so according to the normal block rules.</li>
</ol>
<div>
It's really easy to put this in use, just call the timer method and give it a completion block:</div>
<div class="p1">
<br /></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> </span><span class="s4">NSTimer</span><span class="s1">.</span><span class="s3">scheduledTimerWithTimeInterval</span><span class="s1">(</span><span class="s2">5.0</span><span class="s1">, repeats: </span><span class="s2">false</span><span class="s1">)</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1"> { (timeinterval) -> </span><span class="s4">Void</span><span class="s1"> </span><span class="s2">in</span></span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s5"> </span><span class="s3">FLLog</span><span class="s5">.</span><span class="s3">info</span><span class="s5">( </span><span class="s1">"*** Timer Fired ***"</span><span class="s5"> )</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<br />
One of the tricks of this implementation is that we are using the userInfo property of the NSTimer to store our block reference. This allows it to exist for the duration of the lifetime of the NSTimer it's associated with.<br />
<br />
<h2>
NSTimer Block Weak</h2>
<br />
One of the advantages of using the NSTimer Block approach is that it doesn't force a retain. So the following is possible:<br />
<br />
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1">class</span><span class="s2"> SimpleTimerTest</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">var</span><span class="s2"> timer : </span><span class="s3">NSTimer</span><span class="s2">?</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">var</span><span class="s2"> timeoutCount : </span><span class="s3">Int</span><span class="s2"> = </span><span class="s1">0</span></span></div>
<div class="p2">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></span></div>
<div class="p3">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s2">deinit</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {</span></span></div>
<div class="p4">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s5">FLLog</span><span class="s4">.</span><span class="s5">info</span><span class="s4">( </span><span class="s2">"SimpleTimerTest deinit"</span><span class="s4"> )</span></span></div>
<div class="p5">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s2">timer</span><span class="s4">?.</span><span class="s2">invalidate</span><span class="s4">()</span></span></div>
<div class="p5">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
<div class="p2">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"></span><br /></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">func</span><span class="s2"> someTask( timeout:</span><span class="s3">NSTimeInterval</span><span class="s2"> )</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {</span></span></div>
<div class="p5">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s1">self</span><span class="s4">.</span><span class="s2">timer</span><span class="s4"> = </span><span class="s3">NSTimer</span><span class="s4">.</span><span class="s2">scheduledTimerWithTimeInterval</span><span class="s4">(timeout, repeats:</span><span class="s1">false</span><span class="s4">)</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> { [weak </span><span class="s1">self</span><span class="s2">] (timeinterval) -> </span><span class="s3">Void</span><span class="s2"> </span><span class="s1">in</span></span></div>
<div class="p4">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s4"> </span><span class="s5">FLLog</span><span class="s4">.</span><span class="s5">info</span><span class="s4">( </span><span class="s2">"*** Timer Fired ***"</span><span class="s4"> )</span></span></div>
<div class="p1">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s2"> </span><span class="s1">self</span><span class="s2">?.</span><span class="s5">timeoutCount</span><span class="s2"> += </span><span class="s1">1</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<div class="p1">
<span class="s2"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></span></div>
<br />
Notice here that we mark the timer block as <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">[weak self]</span>. This means the block will not retain self, but then we are responsible for handling cases where the block might be called without self. Also notice, that we go ahead and invalidate the timer when we deinit. This will release the timer and the block won't be called after the instance goes away. Because we are doing this in deinit, we can actually define the block as <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="s1">[unowned </span><span class="s2">self</span></span><span class="s1"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">]</span></span>:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> func someTask( timeout:NSTimeInterval )<br />{<br /> self.timer = NSTimer.scheduledTimerWithTimeInterval(timeout, repeats:false)<br /> { [unowned self] (timeinterval) -> Void in<br /> FLLog.info( "*** Timer Fired ***" )<br /> self.timeoutCount += 1<br /> }<br />}</span><br />
<br />
We can safely do this because we guarantee that self won't be nil within the block as the block will never be called after deinit (because of the call to invalidate).<br />
<br />
<h2>
Conclusion</h2>
<div dir="ltr" style="background-color: white; color: #666666; font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; font-size: 13.2px; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.6667px; vertical-align: baseline;"><br /></span>
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.6667px; vertical-align: baseline;">I hope you found this helpful and interesting. If you see anything incorrect or if you have different thoughts please share. If you are interested in swift or iOS development, be sure to <a href="http://www.blogger.com/follow-blog.g?blogID=8061157626403355683">follow this blog</a>.</span></div>
<br style="background-color: white; color: #666666; font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; font-size: 13.2px; line-height: 18.48px;" />
<div dir="ltr" style="background-color: white; color: #666666; font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; font-size: 13.2px; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.6667px; vertical-align: baseline;">Thanks,</span></div>
<div dir="ltr" style="background-color: white; color: #666666; font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; font-size: 13.2px; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.6667px; vertical-align: baseline;">Tod Cunningham</span></div>
<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com2tag:blogger.com,1999:blog-8061157626403355683.post-67021938188851195032015-10-14T11:53:00.002-07:002015-10-14T11:53:36.272-07:00Swift Optionals Questions (?) and Bangs (!)<span id="docs-internal-guid-2f04124c-6796-9bbd-5926-4a4c765ab0eb" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">I haven’t posted in awhile, but with the Swift 2.0 release, I figured it was time to dip my toe back into the swift waters. I wanted to share my notes and commentary on optionals.</span><br />
<br />
<h2 dir="ltr" id="docs-internal-guid-2f04124c-6796-bbed-f42b-7152dc7795e3" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Optional Types</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Optional types provide a way to indicate that a value may be nil as opposed to having a value of some given type. An optional is represented in swift via a simple template enum:</span></div>
<br /><div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">enum Optional<T> : NilLiteralConvertible {</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">case None</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">case Some(T)</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">...</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">So you can declare and use an optional variable like any other enum:</span></div>
<br /><div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature : Optional<Float> = .None</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if temperature == .None {</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> temperature.Some = Optional<Float>(70.6)</span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br /><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Given how prevalent and useful optional values are the Swift compiler has built in support for special handling of optionals through the ? and ! operators (syntactic sugar). In addition, swift features such as literal convertibles enable the Optional type to convert nil to/from Optional.None. Thus we can write the above as follows:</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><br />
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature : Float? = nil</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if temperature == nil {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> temperature = 70.6</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br />
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The swift ? operator is used to specify that the value is an Optional and the compiler will automatically represent or wrap that value in an optional.</span><br />
<br />
<h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">The ? operator </span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The example above is using the ? operator. </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.6667px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline;">The ? operator means the value/type is an Optional</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">. It’s really just some syntactic sugar to make code more readable. When used on a variable type declaration, this tells swift to treat/convert the type to an Optional type. Thus the following are 100% equivalent:</span></div>
<br /><div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature : Float? = .None</span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature : Optional<Float> = .None</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">In addition, because Optional types support </span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">NilLiteralConvertible </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">the .None can be replaced with nil as well:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
</div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
</div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature : Float? = nil</span><span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></div>
<div dir="ltr" style="line-height: 1.5; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: white; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature : Optional<Float> = nil</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Now let’s get to how we set and access Optional values. </span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><br id="docs-internal-guid-2f04124c-6797-ca50-9355-1872468d7216" />
<h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Wrapping and Unwrapping</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Keeping with our same example, you can see where the value 70.6 is automatically wrapped (converted to an optional):</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">temperature = 70.6 </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">// Auto wrapped</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">temperature = Optional<Float>(70.6)</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">// Explicitly wrapped</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The swift compiler knows when we are assigning into a Optional and will </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">automatically wrap</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> the value into an Optional. Note: This auto wrapping doesn’t work for other types. It is special to the Optional type.</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The question is how do we get the value back out of an optional? If you try to just access the value, you will get a compiler error as the types don't match:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let currentTemperature : Float = temperature // ERROR, TYPE MISMATCH</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> We could do it like one does it for any enum by using a switch statement:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let currentTemperature : Float </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">switch( temperature )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">{</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">case .None: throw someError</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">case .Some(let value): currentTemperature=value</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">However, this is a rather long winded way of getting access to the value and would destroy code readability if this had to be done every time an Optional’s value was needed. So Swift has several ways to unwrap an optional value:</span></div>
<br /><ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The ! operator can be used to specify the value is an optional and thus may be nil, but the optional will be </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">implicitly unwrapped </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">automatically upon access. With ! if you try to access the value and it’s nil you will get an exception/crash.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The optional binding method uses an </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">if let</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> statement to safely unwrap an optional</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">guard </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">statement is another form of optional binding that safely unwraps an optional</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">optional chaining </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">method allows safe chaining of operations that return optionals</span></div>
</li>
</ol>
<br /><h2 dir="ltr" id="docs-internal-guid-2f04124c-6798-43ac-13bb-6e5af5a62c7d" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Implicitly Unwrapping (!)</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The ! operator can be used to specify the value is an optional and thus may be nil, but the optional will be </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">implicitly unwrapped </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">automatically upon access. With ! if you try to access the value and it’s nil you will get an exception/crash. Because of this, you need to use ! carefully.</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Keeping with our same example, you can force temperature to unwrap its operational by using the ! operator. However, an exception will be thrown if the value is nil: </span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let currentTemperature : Float = temperature! </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">// Exception thrown if nil</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">You can make this safer by checking against nil before you try and access the value:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if temperature != nil {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> let currentTemperature : Float = temperature!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> print( “\(currentTemperature )” )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">You can also use a ! operator in the declaration of a variable such as:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">var temperature2 : Float! = 72.3</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">When used in the variable declaration or function parameter, the variable will be treated as an optional just let the ? operator. However, it will be automatically unwrapped on access. So the following will work:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let currentTemperature : Float = temperature2 // temperature2 auto unwrapped</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">However, if temperature2 is nil an exception will be thrown so use this carefully. Swift also has several ways to unwrap optionals safely.</span></div>
<br /><h2 dir="ltr" id="docs-internal-guid-2f04124c-6798-8636-98d0-39e29e36bf2f" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Optional Binding (if let)</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">To help with unwrapping of optionals in a safe way, swift has a special if let operation that only succeeds when an optional isn’t nil. So building on our example above, we can use if let to safely unwrap temperature to currentTemperature:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if let currentTemperature = temperature {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // Only get here if temperature != nil</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // currentTemperature will have a value</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // currentTemperature’s scope is only this block</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> print( “\(currentTemperature )” )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Extra conditions that have to be met can be added via the where operator:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if let currentTemperature = temperature where currentTemperature < 32.0 {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // Only get here if temperature != nil</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // currentTemperature will have a value less than 32.0</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // currentTemperature’s scope is only this block</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> print( “It’s freezing \(currentTemperature )” )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">One of the issues with optional binding is you can end up with a fair amount of nesting (<a href="http://blog.scottlogic.com/2014/12/08/swift-optional-pyramids-of-doom.html">pyramid of doom</a>). Swift 1.2 helped this out a little bit by allowing you to specify multiple optionals:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if let currentTemperature = temperature,</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> let value2 = optional2 where currentTemperature < 32.0 {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // Only get here if temperature != nil and optional2 != nil</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // currentTemperature will have a value less than 32.0</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> // currentTemperature’s scope is only this block</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> print( “It’s freezing \(currentTemperature )” )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">However, since the unwrapped values (</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">currentTemperature, value2</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">), are only accessible within the scope of the if let block it can still force unwanted nesting. Swift 2.0 introduced guards to help with this problem.</span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><br id="docs-internal-guid-2f04124c-6798-b729-2a8b-064fc954eb71" /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Guards</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Swift 2.0 introduced the concept of guard statements. Guards can be looked at in some ways as the opposite of if let optional binding. Guard statements execute only if the optional’s value is nil as opposed to if let executing only if the optional isn’t nil. Guards also allow the assigned unwrapped non-nil value to be used after the guard statement. </span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">guard let currentTemperature = temperature else {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> print( “Unknown temperature” )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> return // Must exit calling scope of guard</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">}</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">// currentTemperature exists and is non-nil after the guard!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">print( “\(currentTemperature )” )</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">The code executed by the guard when the optional is nil must exit the calling context of the guard statement. If the guard statement is in a loop then continue or break may be used. If the guard is in a function then return is typically used. Basically, execution within the context of the block of code containing the guard isn’t allowed to continue beyond the guard statement when the guarded optional is nil. </span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><br id="docs-internal-guid-2f04124c-6798-e45f-4aa9-bddefae55a2a" /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Optional Chaining</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Optional chaining allows you to place a ? operator after the optional value on which you wish to call a property, method, etc. This will force an optional result to be returned, and if the unwrapped optional is nil then the chain stops and nil is returned. For example:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let optionalValue = anOptional?.aProperty // somevalue would be an optional</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">if let value = optionalValue {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">print( “aProperty = \(value)” )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">As this is called optional chaining, these can be chained as needed. For example:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> let optionalValue = optional?.optionalProp1?.nonOptionalProp.optionalProp2</span><br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">If optional, optionalProp1, or optionalProp2 is nil then nil will be returned as the optionalValue.</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Of course these can also be intermixed with the ! operator when you want to force an unwrap. However, if the implicit unwrapped value is nil an exception/crash will happen. For example:</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let optionalValue = optional!.optionalProp1?.nonOptionalProp.optionalProp2!</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">In the above example if optional is nil then as exception/crash will happen. If optionalProp1 is nil then nil will be returned and optionalProp2 won’t get evaluated. If optionalProp2 isn’t nil but optionalProp2 is nil then it will exception/crash.</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">If the ? operator isn’t used in the chain then the actual value will be returned as opposed to an optional value. For example.</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">let value = optional!.optionalProp1!.nonOptionalProp.optionalProp2!</span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> In the above example value will be the value of optionalProp2, unless one of the optionals is nil in which case you will get an exception/crash so this is very much unsafe and would be of bad practice!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Quick Summary: Questions (?) and Bang (!)</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">When you see the ? operator it means the value is an optional and thus may be nil. When you see ! it also means the value is an optional and thus may be nil, but the optional will be implicitly unwrapped automatically upon access. With ! if you try to access the value and it’s nil you will get an exception/crash.</span></div>
<br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">Conclusion</span></h2>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">I hope you found this helpful and interesting. If you see anything incorrect or if you have different thoughts please share. </span></div>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Thanks,</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;">Tod Cunningham</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<h2>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline;">References:</span></h2>
<ul>
<li><a href="http://nshipster.com/swift-1.2/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">http://nshipster.com/swift-1.2/</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span><br /><a href="http://nshipster.com/swift-literal-convertible/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">http://nshipster.com/swift-literal-convertible/</span></a><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;"> </span></li>
<li><a href="http://www.codingexplorer.com/the-guard-statement-in-swift-2/"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">http://www.codingexplorer.com/the-guard-statement-in-swift-2/</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></li>
<li><a href="http://blog.scottlogic.com/2014/12/08/swift-optional-pyramids-of-doom.html"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">http://blog.scottlogic.com/2014/12/08/swift-optional-pyramids-of-doom.html</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></li>
<li><a href="http://www.touch-code-magazine.com/swift-optionals-use-let/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">http://www.touch-code-magazine.com/swift-optionals-use-let/</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></li>
<li><a href="http://lithium3141.com/blog/2014/06/19/learning-swift-optional-types/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">http://lithium3141.com/blog/2014/06/19/learning-swift-optional-types/</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></li>
<li><a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline;">https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline;"> </span></li>
</ul>
<br /><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0tag:blogger.com,1999:blog-8061157626403355683.post-40623228179734825182014-06-23T18:09:00.000-07:002014-06-23T18:09:34.674-07:00Advanced Swift - Part 2<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP97YDR5lrjQnrD81_A3kHwXXfAVytxgt0u-eyCvZGmdMATpVPRFRRfmz13z61Vy1hguTJNs-3An4GWwqhuHcXjPgkPnepPwXNaBMxX6y7ABKnne90Gt8zmyZCE0lZSvH7ZXHsFMhIvkSu/s1600/home-hero-swift-hero-small.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP97YDR5lrjQnrD81_A3kHwXXfAVytxgt0u-eyCvZGmdMATpVPRFRRfmz13z61Vy1hguTJNs-3An4GWwqhuHcXjPgkPnepPwXNaBMxX6y7ABKnne90Gt8zmyZCE0lZSvH7ZXHsFMhIvkSu/s1600/home-hero-swift-hero-small.png" /></a></div>
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. You can find <a href="http://blog.fivelakesstudio.com/2014/06/advanced-swift-part-1.html">Part 1 here</a>.<br />
<br />
I have also attached a <a href="http://www.fivelakesstudio.com/download/Blog/AdvancedSwiftPart2.playground.zip">swift playground file</a> with the sample code for part 2.<br />
<div>
<br />
<br /></div>
<h3>
Swift Language Protocols</h3>
<div>
<br /></div>
<div>
In swift, you can hook into language features by using special protocols. Swift is very much a protocol based language. Some of the language protocols include:<br />
<br />
<center>
<table>
<tbody>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">LogicValue</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">if LogicValue {</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">Printable</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">"\(printable)</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">Sequence</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">for x in sequence</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">IntegerLiteralConvertible</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">65536</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">FloatLiteralConvertible</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">1.0</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">StringLiteralConvertible</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">"abc"</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">ArrayLiteralConvertible</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">[ a, b, c ]</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">DictionaryLiteralConvertible</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">[ a:x, b:y ]</span></td>
</tr>
<tr>
<td><span style="font-family: Courier New, Courier, monospace;">Equatable</span></td>
<td><span style="font-family: Courier New, Courier, monospace;">x == y</span></td>
</tr>
</tbody></table>
<div style="text-align: left;">
<br /></div>
</center>
<center style="text-align: left;">
Let's look at a simple example of implementing the <span style="font-family: Courier New, Courier, monospace;">Printable</span> protocol that allows you to provide a custom description that will be used by <span style="font-family: Courier New, Courier, monospace;">println</span>.</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUPvnFQrv1V_OHUjjC2tvT0UdmXazicaRNdYyNraKJUCBJbe88exYz5NXjy0Ff3MGwocBraNbp5-ZOoNprNLAXpDxDvjxfyCtXECcN6uA-smmfbV96ipTAJcfOYmR6iX7S4ks6hZ_u8a7f/s1600/2014-06-23_12-10-40.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUPvnFQrv1V_OHUjjC2tvT0UdmXazicaRNdYyNraKJUCBJbe88exYz5NXjy0Ff3MGwocBraNbp5-ZOoNprNLAXpDxDvjxfyCtXECcN6uA-smmfbV96ipTAJcfOYmR6iX7S4ks6hZ_u8a7f/s1600/2014-06-23_12-10-40.png" /></a></div>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
Unfortunately when using the playground, the Printable protocol isn't used. I assume this will be fixed at some point.</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<h3>
<center style="text-align: left;">
Subscript Declarations</center>
</h3>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
You can use Swift's subscript declarations to add subscripts and even support for subscript ranges. Here is a useful example adapted from a <a href="http://stackoverflow.com/questions/24092884/get-nth-character-of-a-string-in-swift-programming-language/24178591#24178591">Stack Overflow post</a> that extends the String class to add subscript access to Strings.</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF67nj3y2iEtwLzpMAiqYBx_8LLLl1v0sXExf0r3Hfl1wtVEc1_Dy_BxYVOyOTFHHMcZBgwmTDochiH_FfUr03kB5eXMKnjeN93bzR520UW2p9IWDfcew_eEHEG3OxKGCWWvQx36Dejxs2/s1600/2014-06-23_17-46-23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF67nj3y2iEtwLzpMAiqYBx_8LLLl1v0sXExf0r3Hfl1wtVEc1_Dy_BxYVOyOTFHHMcZBgwmTDochiH_FfUr03kB5eXMKnjeN93bzR520UW2p9IWDfcew_eEHEG3OxKGCWWvQx36Dejxs2/s1600/2014-06-23_17-46-23.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
This allows for natural String manipulations, <i>which I think should actually be built into Swift</i>:</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<center style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">var string = "abcdef"</span></center>
<center style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">var firstChar = string[0]</span></center>
<center style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">var subString = </span><span style="font-family: 'Courier New', Courier, monospace;">string</span><span style="font-family: Courier New, Courier, monospace;">[0...2] // </span><span style="font-family: 'Courier New', Courier, monospace;">subString</span><span style="font-family: Courier New, Courier, monospace;"> equals "abc"</span></center>
<center style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">var subString2 = </span><span style="font-family: 'Courier New', Courier, monospace;">string</span><span style="font-family: Courier New, Courier, monospace;">[2..4] // </span><span style="font-family: 'Courier New', Courier, monospace;">subString2</span><span style="font-family: Courier New, Courier, monospace;"> equals "cd"</span></center>
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<i><br /></i></center>
<center style="text-align: left;">
<i>While you can have your subscript code perform arbitrary work, care should be used to make them behave in a way that is consistent with what people would expect subscripts to do.</i></center>
<center style="text-align: left;">
<i><br /></i></center>
<h3>
<center style="text-align: left;">
Operator Overloading</center>
</h3>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
Swift also supports operating overloading.<i> I'm not a fan of operating overloading as I think it creates maintainability issues. I would advice to use operating overloading very cautiously.</i></center>
<center style="text-align: left;">
<i><br /></i></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<b>
Operators are defined using global functions</b> so they are available outside the scope of the classes they work with:</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFzN3Qw4lCBqHKWIaHvXRuLZXRRmthfh-d5VpJa6gX6861dfjDV8feDPC0dXcTqrto_YEGbTkEcLSFnYfHbnqGKxV4_EoMs-eCJCBfx8I9tIKWPtXKYN9EQf-9qs88A0vMIvLff9Zq2wiy/s1600/2014-06-23_13-01-58.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFzN3Qw4lCBqHKWIaHvXRuLZXRRmthfh-d5VpJa6gX6861dfjDV8feDPC0dXcTqrto_YEGbTkEcLSFnYfHbnqGKxV4_EoMs-eCJCBfx8I9tIKWPtXKYN9EQf-9qs88A0vMIvLff9Zq2wiy/s1600/2014-06-23_13-01-58.png" /></a></div>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
We also added a new method to our Thing class which is nameWithArticle so it can provide a basic implementation of using "a" vs "an".</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXlGh67Tx1d7O0Ka2ETHMHg5DtqhYtNT9jIK1j1H8k-OTc1bTLbhOawcqc1RmymJwZhVr-HO89VN4t6fOSD4nXk_13m3MjzwFacKujlKDj6Y0jdiLl4jgmj0SGTYLiA468PJ8VnV2qm7K1/s1600/2014-06-23_13-35-51.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXlGh67Tx1d7O0Ka2ETHMHg5DtqhYtNT9jIK1j1H8k-OTc1bTLbhOawcqc1RmymJwZhVr-HO89VN4t6fOSD4nXk_13m3MjzwFacKujlKDj6Y0jdiLl4jgmj0SGTYLiA468PJ8VnV2qm7K1/s1600/2014-06-23_13-35-51.png" height="202" width="640" /></a></div>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
</div>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<center style="font-size: medium; font-weight: normal; text-align: left;">
</center>
<center style="font-weight: normal; text-align: left;">
The next feature is one that I was hoping Apple was going to bring to Objective-C and that is Generics.</center>
</center>
<br />
<center style="text-align: left;">
<center style="font-weight: normal; text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
<center style="text-align: left;">
Generics</center>
</h3>
</center>
<br />
<center style="text-align: left;">
<center style="font-weight: normal; text-align: left;">
Generics is a powerful concept that allows you to reuse code while preserving and leveraging strong typing. In fact, we have already used generics (see the Range parameter under Subscript Declarations). No more using an <span style="font-family: Courier New, Courier, monospace;">id,</span> <span style="font-family: Courier New, Courier, monospace;">NSObject,</span> or in Swift the <span style="font-family: Courier New, Courier, monospace;">Any</span> type unless you need something to be truly typeless such as a collection that can hold multiple types or for dynamic polymorphism.</center>
</center>
<center style="text-align: left;">
<center style="font-size: medium; font-weight: normal; text-align: left;">
<br /></center>
</center>
<center style="text-align: left;">
Here is a simple example that shows a generic function that just prints the given value to the console and then returns that value back out. </center>
<br />
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxpfFk7DlDVCx79jTjZBFqQL3nHayMCMM6FaG-vpgbvrm2aV6Mb-I6IRTo7obxIJjKSGOnjletx439RE6qDGPgHeaZ5-jFSNtCJEZ6_mvRIud5yDch-MvjAbe8Wjpm3PoKMzdYFPAzPUDT/s1600/2014-06-23_18-26-03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxpfFk7DlDVCx79jTjZBFqQL3nHayMCMM6FaG-vpgbvrm2aV6Mb-I6IRTo7obxIJjKSGOnjletx439RE6qDGPgHeaZ5-jFSNtCJEZ6_mvRIud5yDch-MvjAbe8Wjpm3PoKMzdYFPAzPUDT/s1600/2014-06-23_18-26-03.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
Most compilers treat generics as templates and generate additional code for each type instance of the generic. However, Swift doesn't to do this. It only has one instance of the code for its generics. In addition, the Swift compiler generates more efficient code when it can make optimizations based on the type. </center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
You can also constrain the type information to force it to conform to a protocol. This allows the compiler to know what operations can be performed by the type. For example:</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja9my_22qvTsNuvMCXt43AW-25LIqr09nvjgYoSvi3_y0Bnqsq2iBF8Di0Nmi8hzLFAFnSeF8Dt8o_cq-5iMxoRL_nTRTDcu6kWutB9Oy5J9dRSooBtgewQBphMIvja5QtZsJ5YKHuaaw2/s1600/2014-06-23_18-59-38.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja9my_22qvTsNuvMCXt43AW-25LIqr09nvjgYoSvi3_y0Bnqsq2iBF8Di0Nmi8hzLFAFnSeF8Dt8o_cq-5iMxoRL_nTRTDcu6kWutB9Oy5J9dRSooBtgewQBphMIvja5QtZsJ5YKHuaaw2/s1600/2014-06-23_18-59-38.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
The above example uses the <span style="font-family: Courier New, Courier, monospace;">Equatable</span> protocol to let the compiler know it can perform the "==" operator. There is a lot more on equatable and generics in the session, and I encourage you to watch it. There is some very cool stuff that Swift can do with its generic system. There is a mind blowing example of a generic "memorize" function that is worth studying.</center>
<center style="text-align: left;">
<br /></center>
<center style="text-align: left;">
</center>
<center style="text-align: left;">
<h3>
</h3>
<h3>
Wrap Up</h3>
<br />
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.<br />
<br />
You can <a href="http://www.fivelakesstudio.com/download/Blog/AdvancedSwiftPart2.playground.zip">download the playground file</a> 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.<br />
<br />
Thanks,<br />
Tod Cunningham<br />
Five Lakes Studio, LLC<br />
co-founder</center>
<div>
</div>
</div>
Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0tag:blogger.com,1999:blog-8061157626403355683.post-14304089094233208902014-06-19T07:00:00.000-07:002014-06-19T07:00:00.059-07:00Advanced Swift - Part 1<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5sXzzMAPyl9HKcZq-Hx4gK1SoWslah5ggXQ9J4cu6coRgR3bosDbYJYFwYYUfE41ofXskpb_eJw65F1RwrDX8IGWL9kcDUzKf6kpCGUXu42rKZm7ZIcaXnC_JeeGxcKPqLEs2cdclZlxG/s1600/home-hero-swift-hero-small.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5sXzzMAPyl9HKcZq-Hx4gK1SoWslah5ggXQ9J4cu6coRgR3bosDbYJYFwYYUfE41ofXskpb_eJw65F1RwrDX8IGWL9kcDUzKf6kpCGUXu42rKZm7ZIcaXnC_JeeGxcKPqLEs2cdclZlxG/s1600/home-hero-swift-hero-small.png" /></a></div>
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. :)<br />
<br />
I have also attached a <a href="http://www.fivelakesstudio.com/download/Blog/AdvancedSwiftPart1.playground.zip">swift playground file</a> with the sample code.<br />
<br />
<h3>
<br /></h3>
<h3>
The Simple Thing Class</h3>
<br />
The first class the session introduced was the "Thing" class. It's fairly basic, so I went ahead and completed its implementation. <i>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.</i><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIpWy5kEUXRp5J8BiNUmZATESBTlJgMZVJ8H8y052-jRIiuQ_43d72sAKM5Hk2wHLmyqFlcA1Q0LYHAHJnQGpnCmrf9sHgmLQIeV6Z6-UmqFMiC3c2j0JRVVG-YdlwAV_l_ytq43bAAGrf/s1600/2014-06-18_21-10-22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIpWy5kEUXRp5J8BiNUmZATESBTlJgMZVJ8H8y052-jRIiuQ_43d72sAKM5Hk2wHLmyqFlcA1Q0LYHAHJnQGpnCmrf9sHgmLQIeV6Z6-UmqFMiC3c2j0JRVVG-YdlwAV_l_ytq43bAAGrf/s1600/2014-06-18_21-10-22.png" /></a></div>
<br />
The location can be nil (no object) so it uses the "?" modifier. We can easily create an instance of "Thing" using named parameters:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEXWzOvSzMIlzTd_scXd8BgFzCePljsycHgiul9rFX6BQvCTNZ9PfFUEwTluQK3uO9VAdLQZwpbL7Q7AE1nU3BSLiuyT8Rl35sfIxz9QjBFTnt8zg0-gG5mkmMSd9VUnSEBJOW8feEJFBd/s1600/2014-06-18_21-26-06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEXWzOvSzMIlzTd_scXd8BgFzCePljsycHgiul9rFX6BQvCTNZ9PfFUEwTluQK3uO9VAdLQZwpbL7Q7AE1nU3BSLiuyT8Rl35sfIxz9QjBFTnt8zg0-gG5mkmMSd9VUnSEBJOW8feEJFBd/s1600/2014-06-18_21-26-06.png" height="16" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
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.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
Full Argument Names</h3>
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEoufxwHw59fKGuGApJHbsvae7nItCMXeG9k-vu45SBSTDBdAIt2AdVYanc3snSm-qYrBGRuSanLxHggVwHDt9Qdpn1VYeGDyrnChrFqgwxcH4pUPNo4uKulf9RKIyGvs-c1B5VlXjOh82/s1600/2014-06-18_22-15-59.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEoufxwHw59fKGuGApJHbsvae7nItCMXeG9k-vu45SBSTDBdAIt2AdVYanc3snSm-qYrBGRuSanLxHggVwHDt9Qdpn1VYeGDyrnChrFqgwxcH4pUPNo4uKulf9RKIyGvs-c1B5VlXjOh82/s1600/2014-06-18_22-15-59.png" /></a></div>
<br />
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.<br />
<br />
<h3 style="clear: both; text-align: left;">
Anonymous Wildcard Expressions (_)</h3>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
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.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_4EgEnlJuvr4yIvk8lYeHNiH2VP49PX-YfWe4-PwrtIkjjqH5Qg0xt7XupHpvgTllfnhs1h9zQlIWq1iD5qVLoC0S3xi4DmJlySrnjbwyTb6L0ejL35IkgHirAViygR3qFXEFtpn-TfH1/s1600/2014-06-18_22-23-04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_4EgEnlJuvr4yIvk8lYeHNiH2VP49PX-YfWe4-PwrtIkjjqH5Qg0xt7XupHpvgTllfnhs1h9zQlIWq1iD5qVLoC0S3xi4DmJlySrnjbwyTb6L0ejL35IkgHirAViygR3qFXEFtpn-TfH1/s1600/2014-06-18_22-23-04.png" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can apply the same technique to argument names.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
Anonymous Argument Names</h3>
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKR5-hQyVB-cCWBtZDqN_BRP3eMKBVkdPNMbeBplhHec0kEar8RHEFe0bXKXrzmRn97Q7WFfvARmzhjawQ8FOsTz92eJECu8XAYnDXondEpVfb_mXdRYgyV9LIk0xnPd-nVbo8jixYpDSs/s1600/2014-06-18_22-34-23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKR5-hQyVB-cCWBtZDqN_BRP3eMKBVkdPNMbeBplhHec0kEar8RHEFe0bXKXrzmRn97Q7WFfvARmzhjawQ8FOsTz92eJECu8XAYnDXondEpVfb_mXdRYgyV9LIk0xnPd-nVbo8jixYpDSs/s1600/2014-06-18_22-34-23.png" /></a></div>
<br />
<i>To me this is an example where Swift is giving too much flexibility in its expressiveness and is asking for abuse.</i><br />
<i><br /></i>
<h3>
Protocols</h3>
<br />
Protocols are like Objective-C protocols in that they don't provide an implementation. Here is an example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFFpJyskLK9whKzM11Gn0Vjw66UB6W28I5XgjOQIP-8UcNDphv_yaXiWDkRGYmDosmOTxOdMYtUoEIW6o8l6pXS_iSEzB_TnWZJKapq72iScQbhZERo3zLsr1CAILV-D1eVfIrOUxEjm-6/s1600/2014-06-18_23-36-27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFFpJyskLK9whKzM11Gn0Vjw66UB6W28I5XgjOQIP-8UcNDphv_yaXiWDkRGYmDosmOTxOdMYtUoEIW6o8l6pXS_iSEzB_TnWZJKapq72iScQbhZERo3zLsr1CAILV-D1eVfIrOUxEjm-6/s1600/2014-06-18_23-36-27.png" /></a></div>
<br />
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.<br />
<br />
<h3>
Testing for Protocol Conformance</h3>
<br />
You can use a conditional cast to check if an object conforms to the protocol. <b><span style="color: red;">However, the example given in the session was incorrect</span></b>. When trying to compile it, I kept getting an error "<span style="color: red;">cannot downcast from 'Thing' to non-@objc protocol type 'Pullable'</span>". 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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBTdmUvuShnUy3voklVDBRj8RBz-ZwkiaDOz9lDB_toz3LPkbHKhjh8ra8UJcSa09xbwbbhyphenhyphenCN6vDcXBZ4L7s4FW-vZAs9edfC7cbeLSTISnsMrlIQJQ84rqi73foy8KkWL6FpfGn24J5O/s1600/2014-06-19_00-35-44.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBTdmUvuShnUy3voklVDBRj8RBz-ZwkiaDOz9lDB_toz3LPkbHKhjh8ra8UJcSa09xbwbbhyphenhyphenCN6vDcXBZ4L7s4FW-vZAs9edfC7cbeLSTISnsMrlIQJQ84rqi73foy8KkWL6FpfGn24J5O/s1600/2014-06-19_00-35-44.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
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.<br />
<br />
<h3>
Wrap Up</h3>
<br />
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.<br />
<br />
You can <a href="http://www.fivelakesstudio.com/download/Blog/AdvancedSwiftPart1.playground.zip">download the playground file</a> 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.<br />
<br />
Thanks,<br />
Tod Cunningham<br />
Five Lakes Studio, LLC<br />
co-founderTodhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com1Michigan, USA44.3148443 -85.60236429999997738.5609653 -95.929512799999969 50.068723299999995 -75.275215799999984tag:blogger.com,1999:blog-8061157626403355683.post-16348605428059903422013-07-01T09:40:00.001-07:002013-07-01T09:40:05.083-07:00Newsletter<div>
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 <a href="http://dashboard.appsfire.com/">Apps Fire Booster SDK</a> which I did a <a href="http://blog.fivelakesstudio.com/2012/06/engage-users-in-app.html">blog post</a> 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 <a href="http://jburgessassociates.com/">strategic marketing company</a> and she planted a bug in my ear about collecting e-mail addresses. <br />
<br /></div>
<div>
<h3>
Newsletter Signup</h3>
</div>
<div>
<br />
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 <a href="http://bit.ly/picrosshd">Picross HD</a>.<br />
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrzPtzW157l1t7-GyBMo-FNz3SJ93t-Rp2MjnFA0ElXnnQK2iJhDaQGJqLJJh-ip2xagnQAM-bhbbjIGWMwr0HAL-rOqlbxUK6DRsdlbwjtwEeHSu2I4AEO_FIv8E7lF9fYaqwnU6ne8HU/s1136/iOS+Simulator+Screen+shot+Jun+30,+2013+7.27.51+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrzPtzW157l1t7-GyBMo-FNz3SJ93t-Rp2MjnFA0ElXnnQK2iJhDaQGJqLJJh-ip2xagnQAM-bhbbjIGWMwr0HAL-rOqlbxUK6DRsdlbwjtwEeHSu2I4AEO_FIv8E7lF9fYaqwnU6ne8HU/s400/iOS+Simulator+Screen+shot+Jun+30,+2013+7.27.51+PM.png" width="400" /></a></div>
<br />
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.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbMy_GfeUyWoQ5DOQSaSmYsJsNMTac6m4_nPLRug28kU29UTFVudBqbq7oZnYLgL3Z92eRkqgktkodn5JDMjxMlKdMh18hZEjdUt33ePL3aIl3otveb6dL00wGD7VL0r1xFKo2KUV6lwmY/s573/2013-06-30_20-45-40.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbMy_GfeUyWoQ5DOQSaSmYsJsNMTac6m4_nPLRug28kU29UTFVudBqbq7oZnYLgL3Z92eRkqgktkodn5JDMjxMlKdMh18hZEjdUt33ePL3aIl3otveb6dL00wGD7VL0r1xFKo2KUV6lwmY/s400/2013-06-30_20-45-40.png" width="400" /></a></div>
<br />
<h3>
Mailchimp</h3>
<br />
We are using <a href="http://mailchimp.com/">mailchimp.com</a> 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 <a href="https://github.com/mailchimp/chimpkit">ChimpKit on git hub</a>. 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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
<h3>
Privacy Policy</h3>
<br />
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. <br />
<br />
<h3>
Free Puzzles</h3>
<br />
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:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXeY2D8dATbVJvpPFOVEaAgUclo3YWEJsEDK25CdnIZOoQay2wDfyT2vHCjODf6mLEUmq6pnxDP1qfk59A_G40rXapaLsy5OIQRq1Sm8Xa9QV980YeiY6TrUh06aGXBGSZP6bglCWG2FUs/s583/2013-06-30_21-03-14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="590" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXeY2D8dATbVJvpPFOVEaAgUclo3YWEJsEDK25CdnIZOoQay2wDfyT2vHCjODf6mLEUmq6pnxDP1qfk59A_G40rXapaLsy5OIQRq1Sm8Xa9QV980YeiY6TrUh06aGXBGSZP6bglCWG2FUs/s640/2013-06-30_21-03-14.png" width="640" /></a></div>
<br />
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.<br />
<br />
<h3>
Puzzle Viewer</h3>
<br />
The <a href="http://bit.ly/FLSNewsletterStarter1">puzzle view</a> 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. <br />
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://bit.ly/FLSNewsletterStarter1"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp38Ps3uYUvjqqJCs-WnX5F5AmUX5UcZPqdaLiBfFMF6dic1x1EfzCDfzSrNUZ_Ik72g0V0G4A_aOwo1YSBMvOHI0LQt1o0trJ8UCCVbYJq_pwRGYLHkV38sdKXHpnCVUfQz46mpofbR4b/s640/2013-06-30_21-13-09.png" width="433" /></a></div>
<br />
It was a little tricky to get it to work, just <a href="mailto:support@fivelakesstudio.com">contact me</a> if you would like me to share the Javascript code with you or you can <a href="http://bit.ly/FLSNewsletterStarter1">view the page</a> source to see it yourself.<br />
<br />
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.<br />
<br />
<h3>
Cross Promote</h3>
<br />
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 <a href="http://bit.ly/Hashi_">Hashi app</a>.<br />
<br />
We will also use the newsletter to talk about upcoming releases and news we think our users may be interested in hearing about.<br />
<br /></div>
<div>
<h3>
Conclusion</h3>
</div>
<div>
<br />
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.<br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your app marketing experiences. Also, feel free to <a href="http://eepurl.com/y_6v9">signup now for our newsletter</a>. 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. :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5dFh7ilJrBceBF1AZ9YJ09STFhRvXQkO2V_gTWq7-rBT84ozNuzo0uljF2djAa-UXuEV7_TQesBRnrDUcmYMXzekkYsy4gEhjd6fDHU67KnPxXm9UJLnpM2MvwfcTTkOudZjx8z6DgPNm/s132/3273736.jpeg" /></div>
<br />
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.<br />
<div>
<br /></div>
<br /></div>
<div>
<br /></div>
Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0New Hudson, Lyon Township, MI 48165, USA42.5108667 -83.615494716.9888322 -124.9240887 68.0329012 -42.3069007tag:blogger.com,1999:blog-8061157626403355683.post-6501492908250928782013-04-08T08:00:00.000-07:002013-04-08T08:00:10.747-07:00iOS In-App Purchases<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsbh-zsrTd7B5gDxJ5jmLIj8GszPLYjjjZlaRlNOlNUI1YiOFcqi1-gp1RlGRyez1A67yyxBhxNlqsSC6SN92G28lDJtCkSIBZWxwEnZ9Ln8YYePOc7IASAV3imOukYB670U6zXe2xtTwl/s1600/iOS+Simulator+Screen+shot+Apr+7,+2013+11.24.30+AM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsbh-zsrTd7B5gDxJ5jmLIj8GszPLYjjjZlaRlNOlNUI1YiOFcqi1-gp1RlGRyez1A67yyxBhxNlqsSC6SN92G28lDJtCkSIBZWxwEnZ9Ln8YYePOc7IASAV3imOukYB670U6zXe2xtTwl/s320/iOS+Simulator+Screen+shot+Apr+7,+2013+11.24.30+AM.png" width="320" /></a></div>
This is hopefully a concise getting started with in-app purchases article. <a href="http://apps.fivelakesstudio.com/">Five Lakes Studio</a> has had a fair amount of success with leveraging <a href="http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction/Introduction.html">in-app purchases</a>, 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.<br />
<br />
<h3>
<b>Setting Up Your Account</b></h3>
<br />
In order to use in-app purchases you have to complete several steps. A good guide to how to do this is <a href="https://developer.apple.com/library/ios/#technotes/tn2259/_index.html#//apple_ref/doc/uid/DTS40009578">TN2259 Adding In-App Purchase to your iOS and Mac Applications</a>. I would recommend taking some time and reading it thoroughly.<br />
<br />
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.<br />
<br />
<h3>
<b>Creating Test Accounts</b></h3>
<br />
You will also need a test account. These can be created using your iTunes Connect account.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7FBhIlHwJROsA1-UyAMNeKxXEoBVUalg4F_9XTYeuH4xpTKKouQKM1mKaS-GeRShi0mYLdeTJQLC1XdvfVZ7Md8Goj0MykucVKuVusZKjoYBTwDp-U9RRcIRco4EX9Z2k7rwWOvipS_jW/s1600/2013-03-31_16-28-48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7FBhIlHwJROsA1-UyAMNeKxXEoBVUalg4F_9XTYeuH4xpTKKouQKM1mKaS-GeRShi0mYLdeTJQLC1XdvfVZ7Md8Goj0MykucVKuVusZKjoYBTwDp-U9RRcIRco4EX9Z2k7rwWOvipS_jW/s1600/2013-03-31_16-28-48.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgE0KUS20g3-2P6cLvMVnvPiZqpe4aF2F7xoqApV9QXZLQa9GKqKhBi-VIXPGHMTLlYeIL2oi39JBgOoFWMoBPoUssNtfIJDFwf3oFRhXf3xvP1nNP4btu2vfzdOdW6DxLK7FL2a4O4V7S/s1600/2013-03-26_08-35-36.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgE0KUS20g3-2P6cLvMVnvPiZqpe4aF2F7xoqApV9QXZLQa9GKqKhBi-VIXPGHMTLlYeIL2oi39JBgOoFWMoBPoUssNtfIJDFwf3oFRhXf3xvP1nNP4btu2vfzdOdW6DxLK7FL2a4O4V7S/s400/2013-03-26_08-35-36.png" width="400" /></a></div>
<br />
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".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdpX0B1AG89ki8zTR_rER9hsZP4-x5xqVmxkOsbsXHjZ8clETTfnMKCvwZ3JLrT1_gxE3suvzHTJAnFnD4EdABvp3CDhkxfRvpEo8FQM9KCdeVvjrc2wYh6eJONqiGm0gjAKut3cO4vSXZ/s1600/IMG_0355.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdpX0B1AG89ki8zTR_rER9hsZP4-x5xqVmxkOsbsXHjZ8clETTfnMKCvwZ3JLrT1_gxE3suvzHTJAnFnD4EdABvp3CDhkxfRvpEo8FQM9KCdeVvjrc2wYh6eJONqiGm0gjAKut3cO4vSXZ/s320/IMG_0355.PNG" width="180" /></a></div>
<br />
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.<br />
<br />
<h3>
<b>Setting up In-App Purchases</b></h3>
<br />
You setup the items you want to be purchasable via <a href="https://itunesconnect.apple.com/">iTunesConnect</a>. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis-FhTgeEK3FEcpRlInX_kw0du5RBukrR9r7IEakKGPIfuK_Ezoi_rOwCXPeDthZWrSo_8bCiWPmNyluzCZHjREACS8-kM0tr0i6nuOIiFLSNGnAGMnnSL0vYC8lB-OjB-ry5y_lbdidmb/s1600/2013-03-31_16-56-22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis-FhTgeEK3FEcpRlInX_kw0du5RBukrR9r7IEakKGPIfuK_Ezoi_rOwCXPeDthZWrSo_8bCiWPmNyluzCZHjREACS8-kM0tr0i6nuOIiFLSNGnAGMnnSL0vYC8lB-OjB-ry5y_lbdidmb/s400/2013-03-31_16-56-22.png" width="400" /></a></div>
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
<h3>
<b>It's App Time</b></h3>
<br />
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 <a href="http://developer.apple.com/library/ios/#documentation/StoreKit/Reference/StoreKit_Collection/_index.html">StoreKit</a> is used to communicate between your app and the AppStore.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Vu5zzDnYbP3I6sQD-eOeEmb4o_-AEo8RR0jBjOeV0_B4fHcipYnItwiMYufMA9hrMr0jDeqVjvhyphenhyphenx01SRx1MQL32l6sB_F-MGIPjexb63eQ1NXet85y1422JsLDQ6bR42zjqx-tZcKwh/s1600/2013-03-31_17-14-45.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Vu5zzDnYbP3I6sQD-eOeEmb4o_-AEo8RR0jBjOeV0_B4fHcipYnItwiMYufMA9hrMr0jDeqVjvhyphenhyphenx01SRx1MQL32l6sB_F-MGIPjexb63eQ1NXet85y1422JsLDQ6bR42zjqx-tZcKwh/s1600/2013-03-31_17-14-45.png" /></a></div>
<br />
The simplest type of in-app workflow to implement is for built in product delivery. The workflow looks like:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiEhM3dhE5uJRGIoa9PMPLMHVVSG2t7BVpwJf49xX2hYBEFLwlMLjENN3xrN_NhGdNpSLzkQSmn14owu5wCQFX7JYr2Vu3azftJ6ZdiGdi9gewZMv8AGVC5e7fs_cneRYWay3wONaHcUEJ/s1600/2013-03-31_17-15-19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiEhM3dhE5uJRGIoa9PMPLMHVVSG2t7BVpwJf49xX2hYBEFLwlMLjENN3xrN_NhGdNpSLzkQSmn14owu5wCQFX7JYr2Vu3azftJ6ZdiGdi9gewZMv8AGVC5e7fs_cneRYWay3wONaHcUEJ/s400/2013-03-31_17-15-19.png" width="385" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The other workflow is a server based authentication workflow which is significantly more complicated and isn't a focus for this article.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I have made available a class called FLOStoreManager that helps manage the built in product deliver workflow and is part of the <a href="https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git">Five Lakes Studio Open Library project on GitHub</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
FLSOpenLibrary</h3>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I'm happy to make FLOStoreManager available under the MIT license as part of the <a href="https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git">Five Lakes Studio Open Library on GitHub</a>. 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. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<i>NOTE: The FLOStoreManager makes reference to featureId which is equivalent to to the App Store productIdentifier.</i></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="text-align: center;"><br />
</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="text-align: center;">There are 3 main parts to the in product delivery process: Download, Present, and Purchase.</span></div>
<br />
<h3>
<b>Downloading Purchasing Information</b></h3>
<br />
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. <br />
<br />
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. <br />
<br />
The <a href="http://developer.apple.com/library/mac/#documentation/StoreKit/Reference/SKProductsRequest/Reference/Reference.html">SKProductsRequest</a> 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.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: green; font-weight: bold;">-</span> (<span style="color: #b00040;">void</span>)<span style="color: blue;">applicationDidBecomeActive:</span>(UIApplication <span style="color: #666666;">*</span>)<span style="color: #19177c;">application</span>
{
NSSet <span style="color: #666666;">*</span>featureSet <span style="color: #666666;">=</span> [[NSSet alloc] <span style="color: #a0a000;">initWithArray:</span><span style="border: 1px solid #FF0000;">@</span>[<span style="color: #ba2121;">@"ProductId1"</span>, <span style="color: #ba2121;">@"ProductId2"</span>]];
[[FLOStoreManager defaultManager] <span style="color: #a0a000;">startAsyncFetchOfProductForFeatureList:</span>featureSet];
}
</pre>
</div>
<br />
This implementation also does some handy work for you automatically:<br />
<ul>
<li>Auto retry on failed attempts</li>
<li>Sends an <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNotification_Class/Reference/Reference.html">NSNotification</a> (kFeatureListReady) when the feature list has been successfully retrieved.</li>
<li>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 <span style="color: blue; line-height: 16px;">applicationDidBecomeActive </span>which may get called multiple times as users enter and leave the app.</li>
<li>Keeps track of the "registered" features and the product information associated with them</li>
</ul>
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.<br />
<div>
<br />
<ul></ul>
<h3>
<b>Present Purchasable Items</b></h3>
<br />
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.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://itunes.apple.com/us/app/picross-hd-pixel-puzzles/id381551512?mt=8"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhhE_AYTxrfpvGWhgFLTUCMlfhtimGIjkE6aMzaxCcLe3HrrBm_XmjUF4lc9ZlOlts520Efe-8cA4kakChq7ZKmH4p2W-Uz7g6GWhKva2zzqm90s3rz5X39-fKfi1vO4v2v_f3kOB75Jzo/s400/iOS+Simulator+Screen+shot+Apr+7,+2013+12.39.30+AM.png" width="400" /></a></span></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><a href="https://itunes.apple.com/us/app/picross-hd-pixel-puzzles/id381551512?mt=8">Picross HD - Daily Puzzle Pack In-App Purchase</a></td></tr>
</tbody></table>
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. <br />
<br />
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.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">NSString <span style="color: #666666;">*</span>price <span style="color: #666666;">= </span>[[FLOStoreManager defaultManager] <span style="color: #a0a000;">formattedPriceForFeatureId:</span><span style="color: #ba2121;">@"ProductId1"</span>];
</pre>
</div>
<br />
You will also want to take into account some other factors in the UI such as:<br />
<ul>
<li>The act of purchasing an item is done asynchronously so you will probably want something to indicate when a purchasing is in progress,</li>
<li>You will need to handle the notifications when the purchase either completed or failed. </li>
</ul>
<br />
<h3>
<b>Purchase</b></h3>
<br />
The <a href="http://skpaymentqueue/">SKPaymentQueue</a> 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:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">[[FLOStoreManager defaultManager] <span style="color: #a0a000;">startAsyncPurchaseOfFeature:</span><span style="color: #ba2121;">@"ProductId1"</span>];
</pre>
</div>
<br />
Once the request is completed, one of two NSNotifications will be sent:<br />
<ul>
<li>kFeaturePurchased is sent if the purchase is successful. The notification object with be the featureId NSString</li>
<li>kFeaturePurchasedFailed is sent if the purchase failed. The notification object with be the featureId NSString</li>
</ul>
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.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: green; font-weight: bold;">if</span>( [[FLOStoreManager defaultManager] <span style="color: #a0a000;">isFeatureBeingPurchased:</span><span style="color: #ba2121;">@"ProductId1"</span>] )
{
<span style="color: #408080; font-style: italic;">// The feature is in the process of being purchased</span>
}
<span style="color: green; font-weight: bold;">if</span>( [[FLOStoreManager defaultManager] isAnyFeatureBeingPurchased] )
{
<span style="color: #408080; font-style: italic;">// Some feature is being purchased, we don't care which one</span>
}
</pre>
</div>
<br />
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 "<a href="http://developer.apple.com/library/ios/#releasenotes/StoreKit/IAP_ReceiptValidation/">In-App Purchase Receipt Validation on iOS</a>". 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.<br />
<div>
<br />
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.</div>
<br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: green; font-weight: bold;">-</span> (<span style="color: #b00040;">BOOL</span>)<span style="color: blue;">application:</span>(UIApplication <span style="color: #666666;">*</span>)<span style="color: #19177c;">application</span> <span style="color: blue;">didFinishLaunchingWithOptions:</span>(NSDictionary <span style="color: #666666;">*</span>)<span style="color: #19177c;">launchOptions</span>
{
[FLOStoreManager defaultManager]; <span style="color: #408080; font-style: italic;">// Allows us to receive AppStore notification</span>
}
</pre>
</div>
<br />
Once the user starts purchasing items, how do you track what has been purchased?<br />
<br />
<h3>
<b>Purchase Tracking</b></h3>
<br />
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. <br />
<br />
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.<br />
<br />
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 <a href="https://developer.apple.com/library/mac/#documentation/security/Conceptual/keychainServConcepts/iPhoneTasks/iPhoneTasks.html">keychain</a> 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.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: green; font-weight: bold;">if</span>( [[FLOStoreManager defaultManager] <span style="color: #a0a000;">isPurchased:</span><span style="color: #ba2121;">@"ProductId1"</span>] )
{
<span style="color: #408080; font-style: italic;">// The feature has been purchased</span>
}
</pre>
</div>
<br />
<h3>
<b>Conclusion</b></h3>
<br />
Wow you made it this far. This turned out to be a wee bit longer then expected, but I hope you found it useful. <br />
<br />
Please feel free to contribute to the <a href="https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git">FLS Open Library</a>. 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.<br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your in-app purchase experiences.<br />
<br />
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.<br />
<br />
<h3>
<b>References</b></h3>
<br />
<a href="https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git">https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git</a><br />
<a href="https://developer.apple.com/library/ios/#technotes/tn2259/_index.html#//apple_ref/doc/uid/DTS40009578">TN2259 Adding In-App Purchase to your iOS and Mac Applications</a><br />
<a href="http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction/Introduction.html">In-App Purchase Programming Guide</a><br />
<a href="http://developer.apple.com/library/ios/#releasenotes/StoreKit/IAP_ReceiptValidation/">In-App Purchase Receipt Validation on iOS</a><br />
<a href="http://blog.mugunthkumar.com/coding/iphone-tutorial-%E2%80%93-in-app-purchases/">iPhone Tutorial – In-App Purchases By Mugunth Kumar</a><br />
<br />
<br /></div>
Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com1New Hudson, Lyon Township, MI 48165, USA42.5108667 -83.615494716.9888322 -124.9240887 68.0329012 -42.3069007tag:blogger.com,1999:blog-8061157626403355683.post-19555256105565060882013-04-07T07:15:00.000-07:002013-04-07T07:15:18.668-07:00Quick Tip: How to show source code in the blogI 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 <a href="http://hilite.me/">http://hilite.me/</a> by Alexander <a href="http://kojevnikov.com/">Kojevnikov</a>. It has a very simple copy/paste interface that just works. You can also do some customizations and pick between may different styles.<br />
<br />
Using it is as simple as:<br />
<ol>
<li>Paste your source code</li>
<li>Hit Highlight</li>
<li>Copy and paste the HTML</li>
</ol>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://hilite.me/"><img border="0" height="494" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_YtnAbrhWFMrMwuh9F5OCs-u86Le8-zAaZCi9gszuDDd0cRhccIHFEXfLiX939L7dY0Jftnk8xjoXV53TE1F1kszMq1IjrYq7nZgS7r1za76_UOm8XdRSY8xLoa8Llgy00oabS502bSL2/s640/2013-04-07_10-00-05.png" width="640" /></a></div>
<br />
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:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: green; font-weight: bold;">-</span> (<span style="color: #b00040;">void</span>)<span style="color: blue;">alertViewCancel:</span>(UIAlertView <span style="color: #666666;">*</span>)<span style="color: #19177c;">alertView</span>
{
<span style="color: green; font-weight: bold;">if</span>( m_alertBlock <span style="color: #666666;">!=</span> <span style="color: green;">nil</span> )
{
m_alertBlock( kAlertViewCanceled );
m_alertBlock <span style="color: #666666;">=</span> <span style="color: green;">nil</span>;
}
}
</pre>
</div>
<br />
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. <br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear if this was useful and what you do to show source code on the web. <br />
<br />
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com1tag:blogger.com,1999:blog-8061157626403355683.post-63787684742041731052013-03-13T12:10:00.001-07:002013-03-13T12:10:16.415-07:00Cocoa Debugging Tip<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8u67FeMPB53gVyoIkQRE-i8UHSRYJthQ32BDOeaj7yPAR2YJmpq900hUA0Se-wMWdHsS6q-YO8GgFZIH4DZX5fgpDKkhImW2SzkixKj6yB0uK75F8IQFl4UYw6ZBrBIvPz2NYijCmX_q-/s1600/134821212.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8u67FeMPB53gVyoIkQRE-i8UHSRYJthQ32BDOeaj7yPAR2YJmpq900hUA0Se-wMWdHsS6q-YO8GgFZIH4DZX5fgpDKkhImW2SzkixKj6yB0uK75F8IQFl4UYw6ZBrBIvPz2NYijCmX_q-/s1600/134821212.png" /></a></div>
I'm attending my local <a href="http://www.meetup.com/A2-CocoaHeads/">Ann Arbor CocoaHeads</a> meeting tomorrow, and the topic is<br />
Objective Tips. So I thought I would share a tip.<br />
<br />
What do you do when you get a crash due to an uncaught exception such as:<br />
<br />
<blockquote class="tr_bq">
<span style="font-size: x-small;">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:</span></blockquote>
<blockquote class="tr_bq">
<span style="font-size: x-small;">(0x355b012 0x32ffe7e 0x35e64bd 0x354abbc 0x354a94e 0x3313663 <span style="color: red;">0x12f54</span> 0x3f0153f 0x3f13014 0x3f042e8 0x3f04450 0x926b5e12 0x9269dcca)<br />libc++abi.dylib: terminate called throwing an exception</span></blockquote>
<br />
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.<br />
<blockquote class="tr_bq">
<span style="font-size: x-small;">im loo -a 0x12f54</span></blockquote>
This does a image lookup which gives a nice dump including the file and line number of the offending code:<br />
<br />
<blockquote class="tr_bq">
<span style="font-size: x-small;">Address: Picross[0x00012f54] (Picross.__TEXT.__text + 67540)<br />Summary: Picross`__57-[AppDelegate application:didFinishLaunchingWithOptions:]_block_invoke112 + 52 at <span style="color: red;">AppDelegate.m:216</span></span></blockquote>
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeh94AsUDWogvR1gyWxBc_EkriT3kE-U2S0yru8ohSgx-9eQ4BaR0j5C6oowtxYD6VrRmbOlsfe9f9F4dKg-z_dtTT1Wwj39YxIlLjUJjCStwc4mOnueAGE-VOfRzFtQP8akqUqi1oDUe2/s1600/2013-03-13_13-50-33.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="65" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeh94AsUDWogvR1gyWxBc_EkriT3kE-U2S0yru8ohSgx-9eQ4BaR0j5C6oowtxYD6VrRmbOlsfe9f9F4dKg-z_dtTT1Wwj39YxIlLjUJjCStwc4mOnueAGE-VOfRzFtQP8akqUqi1oDUe2/s320/2013-03-13_13-50-33.png" width="320" /></a></div>
<br />
I also find this <a href="http://lldb.llvm.org/lldb-gdb.html">GDB to LLDB guide</a> to be a handy reference of the commands available in LLDB.<br />
<br />
I hope this short quick tip was helpful. <span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;">Please feel free to follow me on twitter at </span><a href="http://twitter.com/#!/fivelakesstudio" style="background-color: white; color: #6699cc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px; text-decoration: none;">@fivelakesstudio</a><span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;">. I would love to hear about your experiences with the debugger or any tips you might have.</span><br />
<span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"><br /></span>
<span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"><br /></span>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0tag:blogger.com,1999:blog-8061157626403355683.post-48981905474741819332012-10-22T14:08:00.002-07:002012-11-01T13:32:50.455-07:00GameCenter Turn Based Matches<br />
We have been looking and doing a major overall to <a href="https://itunes.apple.com/us/app/euchre-hd/id407124620?mt=8">Euchre HD</a>. In particular, we are looking at<br />
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:<br />
<br />
<ul>
<li>Support for "live" and "non-live" matches (turn based)</li>
<li>Support for Timeouts</li>
<li>Improved Game Center match UI</li>
</ul>
<br />
<div>
A really good example to get started with Game Center Turn Based match's is <a href="http://www.raywenderlich.com/5480/beginning-turn-based-gaming-with-ios-5-part-1">Beginning Turn-Based Gaming with iOS 5</a> by Jacob Gundersen. Some API's have been changed in iOS 6, but it is still a really good tutorial.</div>
<div>
<br /></div>
<div>
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.</div>
<div>
<br /></div>
<div>
<b>Passing Turn To Yourself</b></div>
<div>
<br /></div>
<div>
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.</div>
<div>
<br /></div>
<div>
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.</div>
<div>
<br /></div>
<div>
<b>Participant Timeout (new in iOS 6)</b></div>
<div>
<br /></div>
<div>
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.</div>
<div>
<br /></div>
<div>
Another interesting case is when a participant is in a matching state. The timeout isn't applied against that unmatched participant.</div>
<div>
<br /></div>
<div>
<b>Changes to Authentication</b></div>
<div>
<br /></div>
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.<br />
<br />
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.<br />
<br />
<b>Number of Players in a Match (Updated 11/1/2012)</b><br />
<br />
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.<br />
<br />
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.<br />
<br />
Game Center provides a really nice interface for forming a multi-player game. Here is an example, that shows a 2-4 player game.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9j7ozlHH2hCAMDefsVKv6uUTLgxAKkBVRlb8cCE-muBmGnjdS1ti2rvnvdTgw7EwwkcF_Db1IDfMMU2QtQKJRkfkEw7VEEMoyOrxOoUIYu-4jK7uLMwnRH7Paa5i514oSV_3ubrFC5TE2/s1600/2012-11-01_16-06-34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9j7ozlHH2hCAMDefsVKv6uUTLgxAKkBVRlb8cCE-muBmGnjdS1ti2rvnvdTgw7EwwkcF_Db1IDfMMU2QtQKJRkfkEw7VEEMoyOrxOoUIYu-4jK7uLMwnRH7Paa5i514oSV_3ubrFC5TE2/s1600/2012-11-01_16-06-34.png" width="179" /></a></div>
<br />
The play can add or remove players players as long as they stay within the defined min/max limits.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjB5lDLi0csTSFewSB5NeefvZUvrTdD02Ccq6xLufqZvhL0CvPxocQf9rP3QYk2TwHV-9IY6VBkmt1m02yxGUv-XGmNunkcQF02JxVpEACURJCKbxlea2JKgfDqVYK0FPql88vk3LPCnHP/s1600/2012-11-01_16-06-47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjB5lDLi0csTSFewSB5NeefvZUvrTdD02Ccq6xLufqZvhL0CvPxocQf9rP3QYk2TwHV-9IY6VBkmt1m02yxGUv-XGmNunkcQF02JxVpEACURJCKbxlea2JKgfDqVYK0FPql88vk3LPCnHP/s1600/2012-11-01_16-06-47.png" width="179" /></a></div>
<br />
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.<br />
<br />
Here is the example code showing how the request is created.<br />
<br />
<blockquote class="tr_bq">
<span class="s1"> </span>GKMatchRequest<span class="s1"> *request = [[</span>GKMatchRequest<span class="s1"> </span><span class="s2">alloc</span><span class="s1">] </span><span class="s2">init</span><span class="s1">];</span><br />
request.<span class="s2">minPlayers</span> = 2; <br />
request.<span class="s2">maxPlayers</span> = 4;<br />
request.<span class="s2">playersToInvite</span> = playersToInvite;<br />
request.<span class="s2">playerGroup </span>= <span class="s3">0</span>;<br />
request.<span class="s2">defaultNumberOfPlayers</span> = 4;</blockquote>
As anyone else encounter this issues? Any good suggestions on how to handle it? I would rather not write my own custom matchmaking interface.<br />
<br />
<br />
<b>Conclusion</b><br />
<br />
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. :)<br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your experiences Game Center. I hope this was helpful.<br />
<br />
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.<br />
<div>
<br /></div>
<br />
<br />
<br />
<div class="p1">
<br /></div>
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com3tag:blogger.com,1999:blog-8061157626403355683.post-37305098071273486432012-08-31T07:49:00.000-07:002016-01-05T05:59:36.227-08:00NSMutableArray Weak References<br />
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 <a href="http://www.mikeash.com/pyblog/friday-qa-2012-03-09-lets-build-nsmutablearray.html">example by Mike Ash</a> 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.<br />
<br />
So I kept looking and found a great <a href="http://stackoverflow.com/questions/4692161/non-retaining-array-for-delegates">example on Stack Overflow by Mark Powell</a> that takes advantage of Core Foundation's Mutable array. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUDp_IkSkEHJiJEWelyRzeew78pnL9zaiOc_xi5DTJj4f2OTW5_8-k1GB-J6eyaFPNdTlyemVcm6jpo1ui4cTOUvaChzDVw8wTzO2SYjpn9XvZUPi2EX2L3R8_t9QDY5BTnQ0zyvekWXZJ/s1600/2012-08-31_10-39-39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUDp_IkSkEHJiJEWelyRzeew78pnL9zaiOc_xi5DTJj4f2OTW5_8-k1GB-J6eyaFPNdTlyemVcm6jpo1ui4cTOUvaChzDVw8wTzO2SYjpn9XvZUPi2EX2L3R8_t9QDY5BTnQ0zyvekWXZJ/s1600/2012-08-31_10-39-39.png" /></a></div>
<br />
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 <a href="http://bit.ly/NSArrayWeakReference">Download NSArrayWeakReference Source</a>. <br />
<br />
I hope you found this helpful. <br />
<br />
- TodTodhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com1tag:blogger.com,1999:blog-8061157626403355683.post-868022788361812112012-08-27T12:15:00.000-07:002012-08-27T12:15:13.469-07:00Japanese App Store WithholdingI learned an interesting lesson this weekend. I was reviewing our AppStore financial results and I noticed an interesting entry:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXQVhTLrJRpAKH4Ftqy5KJ7koEzYiSbfjtHmRl6j7kDfnYbru62vz6DLoSbVTTG_3sK0j7TSJOlYY74vYjA4PhGOg1LClZiEULlbLFJJr2FetQOolnbxPkIrKSHfBHgCn-iMSFrjn9M8mb/s1600/2012-08-26_17-56-39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXQVhTLrJRpAKH4Ftqy5KJ7koEzYiSbfjtHmRl6j7kDfnYbru62vz6DLoSbVTTG_3sK0j7TSJOlYY74vYjA4PhGOg1LClZiEULlbLFJJr2FetQOolnbxPkIrKSHfBHgCn-iMSFrjn9M8mb/s1600/2012-08-26_17-56-39.png" /></a></div>
<br />
After a little bit of research, I learned Apple withholds a 20% tax on Japanese sales. In order to eliminate this tax, you need to file some tax forms with the Japanese government and US government. Apple helps with this process by providing and submitting the forms.<br />
<br />
David Smith has a nice article on "<a href="http://david-smith.org/blog/2012/02/01/understanding-japanese-app-store-withholding/">Understanding Japanese App Store Withholding</a>" that goes into more detail.<br />
<br />
I filled out the forms this weekend (8/26/2012), and I will report back on when it takes effect. I would love to hear about year experiences with this process.<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com2tag:blogger.com,1999:blog-8061157626403355683.post-62256348607914842832012-08-13T12:09:00.000-07:002013-04-07T07:39:07.018-07:00Subversion to GitA couple weeks ago Ken and I decided to make the plunge from Subversion to Git. The main catalyst for this was some <a href="http://tumult.com/hype/">Hype</a> generated files I wanted to check into Subversion. Unfortunately, every time you generate the HTML for a Hype project it blows away the folder structure, which removes the .svn folder and gets subversion all confused. I understand there are newer versions of Subversion that resolve that issue, but I decided to just do the switchover to Git given that's where it seems most people are going today.<br />
<br />
<h4>
Picking a Hosting Provider</h4>
<br />
Given Ken and I work together on projects we need a version control hosting provider. We currently use <a href="http://beanstalkapp.com/">Beanstalk</a> for subversion, and we have been very pleased with them. However, I decided to take a look at the available options. I took a serious look at <a href="https://github.com/">GitHub</a> and <a href="https://bitbucket.org/">Bitbucket</a>. I opted to go with GibHub for our main git repository. I really liked its interface and how it links your personal account to your corporate account. Plus it has a big user following. Several reviews I read also talked about GitHub being more performant and a step ahead of Bitbucket. However, that info could be a bit dated by now.<br />
<br />
We opted for GitHub's $25 per month plan for 10 private repositories. However, I also created a Bitbucket account as they have free unlimited private repositories. I'm using bitbucket to host paid for 3rd party assets, and I'm using GitHub for our source.<br />
<br />
<h4>
GUI Tools</h4>
<br />
While lots of people use the command line to manage Git, I prefer having some nice GUI tools for my day to day work. There are several tools out there, but I ended up going with SourceTree. It seems to be the most complete tool for managing subversion repositories. I also used <a href="http://mac.github.com/">GitHub's tool</a> for awhile to get up and started, but <a href="http://www.sourcetreeapp.com/">SourceTree</a> feels like a more complete and powerful solution.<br />
<br />
<h4>
Migration</h4>
<br />
I decided not to do a full history migration from Subversion to Git. I opted to just migrate the latest revision. We are a small shop, and it sounded like more trouble then it was worth to preserve the entire history.<br />
<br />
I still made a big mistake though. I just took all our source and added it to Git, just like it was setup in subversion. We have over 1.5 GB of source including game assets such as images, sounds, and puzzle data. This is when I learned that GitHub doesn't recommend repositories over 1GB.<br />
<br />
I learned firsthand how painfully slow it was to pull down a new large repository, and I was also worried that we would get flagged by GitHub for having too large of a repository. I also found I would occasionally get an error downloading the new repository and would have to start over.<br />
<br />
The solution was to breakup the old subversion repository into several smaller repositories and submodules. I haven't had any issues with these smaller repositories.<br />
<br />
<h3>
Submodules</h3>
<br />
I decided to break up the old single subversion repository into several smaller repositories. Each iOS app we make has its own GIT repository, and we use submobiles for shared components.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2N3JCOemUjffcUtI32KTZGQV8ZBIzb0PikhK8UR4dcTO_26hYt_kqkXPGW49d-MApvBwH7AzYmJ3Aalpou2idt98vpik87qRA3GODJqOqxWOqIEgfzc9Vb0FfXPA_9YFDW07HkyVkSfP/s1600/2012-08-13_14-10-27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2N3JCOemUjffcUtI32KTZGQV8ZBIzb0PikhK8UR4dcTO_26hYt_kqkXPGW49d-MApvBwH7AzYmJ3Aalpou2idt98vpik87qRA3GODJqOqxWOqIEgfzc9Vb0FfXPA_9YFDW07HkyVkSfP/s1600/2012-08-13_14-10-27.png" /></a></div>
<br />
This is an example of the submodules used for <a href="https://itunes.apple.com/app/id534414467?mt=8">Hashi</a>, a new App we are working on.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0eJz2YlLxh-caiTcs6A3tIQSfYwt-YbvftF83NwhhXnI8s_6hyphenhyphenWX8iybJFS43yeZuUWDfNBnYq7lVrSz0LaKNG8xdFGKjnjiar1unG_tF1asi2-eev0v-8qeDE3NPw4aR6O0PAsifRuvG/s1600/2012-08-13_14-34-14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0eJz2YlLxh-caiTcs6A3tIQSfYwt-YbvftF83NwhhXnI8s_6hyphenhyphenWX8iybJFS43yeZuUWDfNBnYq7lVrSz0LaKNG8xdFGKjnjiar1unG_tF1asi2-eev0v-8qeDE3NPw4aR6O0PAsifRuvG/s1600/2012-08-13_14-34-14.png" /></a></div>
<br />
What's nice about using submodules is that the parent project references an explicit revision of the submodule. So if a submodule is updated in a different project, it won't break the current project. This allows you the time to upgrade the project at your own connivence.<br />
<br />
One thing we learned is that you have to be a little careful when adding a submodule to your project through SourceTree. By default SourceTree was adding the user's login to the submodules URL. This of course causes issues for other people trying to work with the submodule.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA7oMy8hjxQMHxIhoiW_yFJK1gk67qgR-396jbr_1FmHc_WUkjKYQRSa3tOQlCLmdclaExuPXbNTm4mlVj09UJ0b4YJ7BrzNJ83SieUsOMV935aaT5l8u7gV6HiRddfDpmyzb_oEkJWfSW/s1600/2012-08-11_13-12-28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA7oMy8hjxQMHxIhoiW_yFJK1gk67qgR-396jbr_1FmHc_WUkjKYQRSa3tOQlCLmdclaExuPXbNTm4mlVj09UJ0b4YJ7BrzNJ83SieUsOMV935aaT5l8u7gV6HiRddfDpmyzb_oEkJWfSW/s1600/2012-08-11_13-12-28.png" width="640" /></a></div>
<br />
You just need to remove the user's login from the URL. If you forget, you can manually change the .git/config to reference the correct submodule URL.<br />
<br />
<h3>
Conclusion</h3>
<br />
It took me a weekend or two before I started to understand Git. I'm still far from an expert, but I am getting more comfortable with it. One of the sites that really helped was from Mark Lodato and his <a href="http://marklodato.github.com/visual-git-guide/index-en.html">Visual Git Reference</a>. Stuart Ellis also has a really nice <a href="http://www.stuartellis.eu/articles/git-basics/">basic getting started guide to using Git</a>. And finally the must read <a href="http://gitref.org/branching/">Git Reference on Branching and Merging</a>. <br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your experiences on using or switching to Git. Let me know if you found this useful.<br />
<br />
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com1tag:blogger.com,1999:blog-8061157626403355683.post-68187591592679779962012-07-02T14:12:00.000-07:002012-07-02T14:12:13.630-07:00Hype - How To PlayKen and I have been struggling with the problem of how to teach people to play our games. Most of our games are fairly niche, and we would like to broaden their appeal to people who might not know how to play.<br />
<br />
We wanted something that would accomplish the following goals:<br />
<br />
<ul>
<li>Quickly teach the players the basics of game play</li>
<li>Look integrated into the app</li>
<li>No download or streamed content</li>
<li>Measurable</li>
<li>We don't want to inflate the App size too much</li>
<li>Something we can create without too much custom programming</li>
</ul>
<br />
What we ended up with was a how to play integrated tutorial that was implemented with an imbedded WebView that plays back HTML 5 generated via <a href="http://tumult.com/hype/">Hype</a>. That was a mouth full. Good thing we have a video showing it in action:<br />
<br />
<br />
<br />
<center><iframe allowfullscreen="" class="tscplayer_inline embeddedObject" frameborder="0" height="276" mozallowfullscreen="" name="tsc_player" scrolling="no" src="http://www.screencast.com/users/TodCunningham/folders/Camtasia/media/7d76d945-1311-4c5f-96d5-492c610f4f76/embed" style="overflow: hidden;" type="text/html" webkitallowfullscreen="" width="537"></iframe></center><br />
<br />
<h3>
Hype</h3>
<br />
Using Hype, you can create HTML 5 web content with animations and interactive content. The best part is it creates really small output as it just requires the art assets and some generated javascript to control the animations.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGMEQkYibZH4fJiNkKpm0W2RVut20ZmQ6Qnb6jUSaycG4UMoES2VbJgezAQ4ApI8JJYacak8e5JdUYDef3yqGA7wxQ2NzVFoswiPr2SZQXJd9BZTZ7M7nAxKWDw1qXuMH64R92qBWV4rN3/s1600/2012-07-02_15-17-32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGMEQkYibZH4fJiNkKpm0W2RVut20ZmQ6Qnb6jUSaycG4UMoES2VbJgezAQ4ApI8JJYacak8e5JdUYDef3yqGA7wxQ2NzVFoswiPr2SZQXJd9BZTZ7M7nAxKWDw1qXuMH64R92qBWV4rN3/s640/2012-07-02_15-17-32.png" width="481" /></a></div>
<br />
There are just a view basic types of object you can use in Hype such as Box, Text, Button, ...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKVnb4Y-gQh1pk4TMAO0I_iWKd9rdMMhNLLhcmqMapQvpgZ0mzFcFoeNe5s12CJN02RDxVFLv6AgDKX4x-FglaxNdNkeBXiQgJDZqsm_NivZgraxA4NkFVBOy6yin-qkH7xLc4EzUWgmz1/s1600/2012-07-02_15-23-09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKVnb4Y-gQh1pk4TMAO0I_iWKd9rdMMhNLLhcmqMapQvpgZ0mzFcFoeNe5s12CJN02RDxVFLv6AgDKX4x-FglaxNdNkeBXiQgJDZqsm_NivZgraxA4NkFVBOy6yin-qkH7xLc4EzUWgmz1/s1600/2012-07-02_15-23-09.png" /></a></div>
<br />
I wish Hype had Arrows and other nicer callout objects build into it. However between the art assets I already had and using <a href="http://www.techsmith.com/snagit.html">Snagit</a> for the other assets, I was able to put together what I needed. <br />
<br />
I was actually able to simulate gameplay just by using these basic Hype elements and its <a href="http://en.wikipedia.org/wiki/Key_frame">Key framing</a> capability. It only took one evening to finish the Hype project. I thought about using something like <a href="http://www.techsmith.com/camtasia.html">Camtasia</a> to record a video of some of these parts as opposed to rolling the play animations by hand. However, I wanted the output really small and it wasn't that hard to simulate the effects I needed. However, given you can embed video in Hype it would be interesting to try it with embedded video clips. <br />
<br />
<h3>
HTML</h3>
<br />
You can easily generate the HTML assets for the Hype project. It just produces a simple "main" html file and a folder containing the Javascript, Images, and other resources needed to run the project.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2QASwfJRqP2WSrvQzIfYxcmbHXtg49g-5o3_uuPSisO0QLgprz458hEHsHmaci-ZKWeVVxO0BGdf57jv2onY0VRFs4MxumL8fDP_17FpWw7_WxPSYOYNSCU3OwsSohH9H2fyTkMXUyoH2/s1600/2012-07-02_15-36-10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2QASwfJRqP2WSrvQzIfYxcmbHXtg49g-5o3_uuPSisO0QLgprz458hEHsHmaci-ZKWeVVxO0BGdf57jv2onY0VRFs4MxumL8fDP_17FpWw7_WxPSYOYNSCU3OwsSohH9H2fyTkMXUyoH2/s1600/2012-07-02_15-36-10.png" /></a></div>
<br />
Given this is just HTML, you can even upload it to a website and interact with it directly in a browser:<br />
<br />
<br />
<center><br />
<iframe height="308px" src="http://www.fivelakesstudio.com/HowToPlay/PicrossHD/en/HowToPlay.html" width="468px">&amp;amp;lt;p&amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;</iframe></center><center><br />
</center><center style="text-align: left;">We just took these generated assets and added them to our iOS project so they would be built into the resource bundle. If you do add it to your project, be sure to include it as a <b>folder</b> reference so xcode will preserve the folder layout in the resource folder. Otherwise, it will get flattened into a single folder which could cause issues.</center><br />
<h3>
<center style="text-align: left;">Loading WebView From Resource</center></h3>
<br />
<center style="text-align: left;">You load resource based files into the WebView just like you would load any local file. Here is some example code that loads the above example:</center><center style="text-align: left;"><br />
</center><center style="text-align: left;"><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> NSString *howToPlayDevice = [FLUtil iPad] ? @"iPad" : @"";</span></center><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> NSString *resourcePath = [[NSBundle mainBundle] resourcePath];</span></center><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> NSString *howToPlayPath = [NSString stringWithFormat:</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">@"%@/html/HowToPlay%@.html",</span></center><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> resourcePath, howToPlayDevice];</span></center><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> NSURL *url = [NSURL fileURLWithPath:howToPlayPath];</span></center><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];</span></center><center style="text-align: left;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> [self.howToPlayWebView loadRequest:requestObj];</span></center><div>
<br /></div>
</center><center style="text-align: left;">One final tip, make sure the canvas in Hype is the same size as the WebView so it fits perfectly with no scaling or borders. That's all there is to it. </center><br />
<h3>
<center style="text-align: left;">Measurable</center></h3>
<br />
<center style="text-align: left;">One of the requirements was for us to be able to measure the effectiveness of this effort through <a href="http://www.flurry.com/">Flurry</a>. In order to do that, we need to be able to communicate from the HTML Webview into the Objective-C code. </center><center style="text-align: left;"><br />
</center><center style="text-align: left;">Alexandre Poirot has a nice article on <a href="http://blog.techno-barje.fr/post/2010/10/06/UIWebView-secrets-part3-How-to-properly-call-ObjectiveC-from-Javascript/">How to Properly Call ObjectiveC From Javascript</a>. I didn't need to use his entire framework, but I used the basic concept to allow Hype's Javascript to be intercepted by the WebView's delegate.</center><center style="text-align: left;"><br />
</center><center style="text-align: left;">In Hype, I setup a Javascript function to post to a special URL that can be intercepted by the shouldStartLoadWithRequest UIWebView delegate. </center> <center style="text-align: left;"><br />
</center><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_GH39rz5slxuuD-nwa3lVu3Na30TeJUsg1z0pAP8ZaI7hCB2nVgbWhaWSMBRHX078CTNBJfAHtNyU9-YFbBmDR8HYJQ6JP4QkbtNz29sXymV9S_solgHS6HbfbCwPjDjhYp5jVzWEetr5/s1600/2012-07-02_16-09-19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_GH39rz5slxuuD-nwa3lVu3Na30TeJUsg1z0pAP8ZaI7hCB2nVgbWhaWSMBRHX078CTNBJfAHtNyU9-YFbBmDR8HYJQ6JP4QkbtNz29sXymV9S_solgHS6HbfbCwPjDjhYp5jVzWEetr5/s640/2012-07-02_16-09-19.png" width="640" /></a></div>
<br />
<center style="text-align: left;"><br />
</center><center style="text-align: left;">I used a custom URL scheme called "howtoplayscene" and passed Hype's current scene name so I can tell what scene the user is viewing. By doing this in an iframe that we create and then destroy it so the user doesn't see anything. Plus, we can use the same HTML for the embedded WebView as well as a regular browser. Although, there won't be any tracking when running in a regular browser.</center><center style="text-align: left;"><br />
</center><center style="text-align: left;">Once the javascript is in place, each scene can then be configured to call the trackHowToPlayCreentScene function when it's loaded:</center><center style="text-align: left;"><br />
</center><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNpEfxTQg0YOPaShAaTlflktJBggloddH4-yQzrgGcTckK10grbSgSfJfZKGzqTOrPronxyPpvga9canqGtGknvudHEJAAKxrEajOVVme1MXJn5NImonARV2de-ydKz8dAQHbyc409h0G4/s1600/2012-07-02_16-16-24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNpEfxTQg0YOPaShAaTlflktJBggloddH4-yQzrgGcTckK10grbSgSfJfZKGzqTOrPronxyPpvga9canqGtGknvudHEJAAKxrEajOVVme1MXJn5NImonARV2de-ydKz8dAQHbyc409h0G4/s1600/2012-07-02_16-16-24.png" /></a></div>
<br />
<center style="text-align: left;"><br />
</center><center style="text-align: left;">That's all there is to it on the Javascript side. The Objective-C side is fairly straightforward:</center><center style="text-align: left;"><br />
</center><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMQjK1kkTS8gAopNcH-vJpuJuysANWLvVC1qAS1ANGiSFAZpkSMdOiKqyX-eySg5zz4d2J6Y9AENDrNknLByGQIwLKw_FsvUWwIRy09LS2ELprkgSJY5qTU0lmIUFWcDXLqjtf1rG-Ey9_/s1600/2012-07-02_16-21-48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMQjK1kkTS8gAopNcH-vJpuJuysANWLvVC1qAS1ANGiSFAZpkSMdOiKqyX-eySg5zz4d2J6Y9AENDrNknLByGQIwLKw_FsvUWwIRy09LS2ELprkgSJY5qTU0lmIUFWcDXLqjtf1rG-Ey9_/s1600/2012-07-02_16-21-48.png" /></a></div>
<br />
<center style="text-align: left;"><br />
</center><center style="text-align: left;">With this in place, we will get custom events in Fluury that look something like:</center><center style="text-align: left;"><center style="text-align: left;"><ul>
<li>HowToPlay.Scene.Goal</li>
<li>HowToPlay.Scene.Tool Bar</li>
<li>Show HowToPlay.Scene.Step 1</li>
<li>Show HowToPlay.Scene.Step 2</li>
</ul>
</center><div>
We will be able to track how many users make it through all they steps and which percentage of users drop off at any given point in time. Hopefully, with this information we can help make the tutorial better and find where and if users are getting stuck. We will also be able to correlate information such as the percentage of people that complete the tutorial that go on to purchase.</div>
</center><center style="text-align: left;"><br />
</center><center style="text-align: left;">The other little trick I use, as seen above, is when the user complets the How To Play tutorial. I have the HTML navigate to "<a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html</a>". I picked that URL so when the user hits the done button they will be taken to the webpage for PicrossHD, when run from an external browser. However, when run from within the App, we close the UIWebView.</center> <br />
<h3>
<center style="text-align: left;">Conclusion</center></h3>
<br />
This will go live soon, and we are excited to get this in the hands of our new users. I hope we can teach more people how to Play <a href="http://itunes.apple.com/us/app/picross-hd-pixel-puzzles/id381551512?mt=8">Picross HD</a> and hopefully they will like it.<div>
<br /> Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your experiences on how to onboard people to your app. Let me know if you found this useful, and especially if you now understand how to play Picross HD.<br /><br /> Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>. I should mention that I also work for Techsmith, the makers of Snagit and Camtasia.<br /><br /></div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0tag:blogger.com,1999:blog-8061157626403355683.post-79745969033560600422012-06-18T13:01:00.000-07:002012-06-18T13:53:16.258-07:00Engage Users In-AppKen and I have been trying to figure out how to better engage and communicate with our users. The AppStore sure doesn't make it easy. <br />
<br />
We have tried to use <a href="http://getsatisfaction.com/">GetSatisifaction</a> and of course there is classic <a href="mailto:support@fivelakesstudio.com">e-mail</a>, but they both have the problem of discoverability. We don't have a good spot in App to make those resources available without disrupting the user experience. By forcing users to leave the app and visit our website to communicate with us, we averaged only a few contacts a month.<br />
<br />
We also prompt for star ratings within the app and that has been helpful in getting reviews, and we appreciate and read the review feedback. However, it's really frustrating when you can answer the persons question or problem with no way to actually get the answer to them.<br />
<br />
I happened to find a nice solution to this problem. The <span style="background-color: white;"><a href="http://appsfire.com/appbooster">Appsfire App Booster SDK</a> for iOS and Android is designed to help with in-app engagement. It's still in Beta, but we have been using it for <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a>, and its been great. We now receive feedback a couple times a day from our users, and we are able to respond back to them directly.</span><br />
<span style="background-color: white;"><br /></span><br />
<h3>
Getting Started</h3>
<span style="background-color: white;">First off, we carved out a little space in the UI to put in a messaging button and indicator. Appsfire has several recommendations for this so it has enough visibility within your app. We chose to put it at the top of our main puzzle screen to the right of our App name:</span><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3pphyoC8qHdGJw0fcGdd1mdcdOjr0bGs5RvidaZLtI4W3jJ46JWu7jU7PBSHMovvoNejajMyxi5MTRxeI2S28MrySrj6V2bGuk-2SQJ06v51i3uFl43UlbL6smy5wCzuUKeMuK_htXQ2p/s1600/IMG_0125.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3pphyoC8qHdGJw0fcGdd1mdcdOjr0bGs5RvidaZLtI4W3jJ46JWu7jU7PBSHMovvoNejajMyxi5MTRxeI2S28MrySrj6V2bGuk-2SQJ06v51i3uFl43UlbL6smy5wCzuUKeMuK_htXQ2p/s1600/IMG_0125.PNG" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Message Button With Message Badge</td></tr>
</tbody></table>
They even include a little helper class that takes care of creating the badge for you. We chose to do a custom integration because we have a game style UI.<br />
<br />
We hooked up notifications for message changes so that badge can be updated correctly, and when the little message bubble is pressed we launch the Appsfire messaging interface. That's all you have to do on the client side and you can start engaging your users. I would be happy to share the code we use for this, just send me a <a href="http://twitter.com/#!/fivelakesstudio">tweet</a>.<br />
<br />
<h3>
In-App Messaging</h3>
<div>
Appsfire includes a built-in messaging engine. Your users can send you messages, and you can reply to them directly within the app. </div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpFfomIcZf694x_8F8iXjY28AbjoF0B9rMqnJVTQqZa8w52e7zJZWXao6uUJAw2hSGUkoD5l8Zcaq6vYEsqUzhoRfgZqyvJ4QKHV8YgmPLp43XTcRw5TUD4khUAIFYxjOknoy9otT0ON2/s1600/IMG_0124.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpFfomIcZf694x_8F8iXjY28AbjoF0B9rMqnJVTQqZa8w52e7zJZWXao6uUJAw2hSGUkoD5l8Zcaq6vYEsqUzhoRfgZqyvJ4QKHV8YgmPLp43XTcRw5TUD4khUAIFYxjOknoy9otT0ON2/s1600/IMG_0124.PNG" /></a></div>
<br />
They have options for changing the color scheme, but the default color scheme worked well for us.<br />
<br />
The UI is also supposed to be localized in several languages including German and Japanese. However, we were have never able to confirm that it is indeed localized. I can say that we have many Japanese users that have sent us feedback through Appsfire.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-XixdZW6n1kFY7_A7L5rRuhGYKxhHcjlzZss33d2L6GGa_QVYq97bkzOJaIhrtc8KiEccSsz_UAVijZVkqYXQpMk27eXjCP-WTYy0fhtUp56vZzpclIeL_QJ4umJY5-kCIjLweRTRB2lT/s1600/IMG_0123.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-XixdZW6n1kFY7_A7L5rRuhGYKxhHcjlzZss33d2L6GGa_QVYq97bkzOJaIhrtc8KiEccSsz_UAVijZVkqYXQpMk27eXjCP-WTYy0fhtUp56vZzpclIeL_QJ4umJY5-kCIjLweRTRB2lT/s1600/IMG_0123.PNG" /></a></div>
<br />
The e-mail field is optional. We have found most users do provide an e-mail address. When the feedback is sent, you will get an e-mail that allows you to respond either within the app or via an e-mail (assuming the user provided an e-mail address).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVJ16rm5VdGuOciLFMyLrnvyW6gDJq_a2L2gNttQb2DceXHJxDgv-Cn4qHCd3EQkgT6yD9zI_aCOWmXJsG6670q88t_trOnT8xPengniMCbFhoWWxDGHY3cDW2lkn6yjarflRJwWG-LPqW/s1600/IMG_0041.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVJ16rm5VdGuOciLFMyLrnvyW6gDJq_a2L2gNttQb2DceXHJxDgv-Cn4qHCd3EQkgT6yD9zI_aCOWmXJsG6670q88t_trOnT8xPengniMCbFhoWWxDGHY3cDW2lkn6yjarflRJwWG-LPqW/s640/IMG_0041.PNG" width="584" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
We usually try to answer the user via the "Notification Wall" aka in-app. However, if the response is long or under special circumstances we will reply via e-mail. For example, one user felt strongly about an issue and vowed to never launch the app again. I wanted to thank the user for their feedback and reach out to them. Doing it in-app wouldn't have been effective assuming they weren't going to open the app again so I used e-mail. The user thanked me for reaching out to him and hopefully he gave us another chance.<br />
<br />
<h3>
What's New</h3>
Another feature we use is What's New. The Appsfire server will automatically detect new App releases, and it can automatically notify your users of the update.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNFLbzq7cVWtJlCj2CKMpfTX1cCzr5qTYthLwhB6bfv7k1ToyAKzAKmq1nioeE1KW3N0nTh8qP8b-qkliFjyr9lJGrjQ5EyWbEaJc2VjAPgrLfSZmtbFWT-Ijvr-FhB2OKPvFGTFM-T7-q/s1600/IMG_0122.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNFLbzq7cVWtJlCj2CKMpfTX1cCzr5qTYthLwhB6bfv7k1ToyAKzAKmq1nioeE1KW3N0nTh8qP8b-qkliFjyr9lJGrjQ5EyWbEaJc2VjAPgrLfSZmtbFWT-Ijvr-FhB2OKPvFGTFM-T7-q/s1600/IMG_0122.PNG" /></a></div>
<br />
<br />
<h3>
Tips and Tricks</h3>
We are planning to release a series of tips and tricks for our users. So far we have released one tip, and it has been well received. The Appsfire portal provides metrics on views and clicks for each message so you can measure their effectiveness.<br />
<br />
We think this is a great way to expose users to features or capabilities of our app that they may not know about. When creating custom message you can also specify the message in different languages such as German and Japanese.<br />
<br />
<h3>
Link to Web Content</h3>
In additional to static message, you can link to web content either displayed within the app or via the Safari app (on iOS). We use this for inviting people to join your twitter account and are experimenting with other creative uses such as linking to a youtube help video.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR9N77w5QEPMinPCmVk2AF3OeaR-AoGr_KJV22nVWbjf3ARJ4C9HYYWXjAEDbooXz3J7wQeNtNMSYAwKqadLxhZEpBPpWxEr2703wOmgHy34MvAjr-nQkcl55JUdnwor2PXRSMQ8sh6LDd/s1600/IMG_0040.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR9N77w5QEPMinPCmVk2AF3OeaR-AoGr_KJV22nVWbjf3ARJ4C9HYYWXjAEDbooXz3J7wQeNtNMSYAwKqadLxhZEpBPpWxEr2703wOmgHy34MvAjr-nQkcl55JUdnwor2PXRSMQ8sh6LDd/s1600/IMG_0040.PNG" /></a></div>
<br />
<br />
<h3>
App Promotion</h3>
App promotion is another option available via the Appsfire SDK. We use it in Picross HD to promote <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/Kento.html">Kento</a> and vice-versa.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd7h0RjQwv4p086acS7TeXxjF9vl168XD4i-imSBlSTegFAcCiFXQ-OvIoJDUnqaKa_5gDraHD1CcY9XXJfzYTu8mQ5Es2yg-wPdKhSP5B2-jMj_OtT6IesXLg3BiPykNG_HvWRxVZuOnp/s1600/IMG_0043.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd7h0RjQwv4p086acS7TeXxjF9vl168XD4i-imSBlSTegFAcCiFXQ-OvIoJDUnqaKa_5gDraHD1CcY9XXJfzYTu8mQ5Es2yg-wPdKhSP5B2-jMj_OtT6IesXLg3BiPykNG_HvWRxVZuOnp/s1600/IMG_0043.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
When the user clicks on an App promotion message they are taken directly to the AppStore.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
Badge Updates on Launch Pad</h3>
A new feature they just added was the ability to update the badge on the Launch Pad without having to run the App. This is a great way to help pull people back into the app.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5CA0zE0lHkLFZLDweJFXwlAhIcTlod8r1l8S2eBToakjGbB9QC2zJKfgMzffBV3wp6_zf-XS2qMz1GCOBtm0KR9jajEQx3_DJiaVbwkX4K33L9Z7JzN_n6ub3h-9iPEjCTdvakLCgSicv/s1600/IMG_0034.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5CA0zE0lHkLFZLDweJFXwlAhIcTlod8r1l8S2eBToakjGbB9QC2zJKfgMzffBV3wp6_zf-XS2qMz1GCOBtm0KR9jajEQx3_DJiaVbwkX4K33L9Z7JzN_n6ub3h-9iPEjCTdvakLCgSicv/s1600/IMG_0034.PNG" /></a></div>
<br />
<br />
<h3>
Conclusion</h3>
I highly recommend the<span style="background-color: white;"> </span><span style="background-color: white;"><a href="http://appsfire.com/appbooster">Appsfire App Booster SDK</a>, and it is in Beta!! It still has some rough edges, but even in its Beta form I consider it a must have for Picross HD because of how it allows us to connect with our customers and create a more engaging experience. </span><br />
<span style="background-color: white;"><br /></span><br />
<span style="background-color: white;">Here are some of the improvements I hope they make as they continue to develop the SDK</span><br />
<ul>
<li>The web portal for managing messages is a little rough around the edges. </li>
<ul>
<li>Setting the start and end dates for a message didn't work as expected.</li>
<li>It was challenging getting push badge notification to work and needed Appsfire support. I expect this will get better. It desperately needs debug tools.</li>
<li>Doesn't work behind some firewalls</li>
</ul>
<li>The in-app messaging interface doesn't work behind some firewalls</li>
<li>Feature Request: Only the welcome message allows you to provide "longer" text without having to use a web page. It would be nice for tips and tricks to have a custom message with longer text.</li>
<li>Feature Request: I would love the ability to time message deliver based on days since installing the app (or other in-app usage). Right now all messages are date/time delivered.</li>
</ul>
<br />
<span style="background-color: white;">The team over at Appsfire is very professional and helpful, and I can't say enough nice things about them and their offering.</span><br />
<div>
<div>
<br /></div>
</div>
<div>
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your experiences connecting and engaging with your users. Let me know if you found this useful.</div>
<div>
<br /></div>
<div>
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.<br />
<br />
- Tod</div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com4tag:blogger.com,1999:blog-8061157626403355683.post-17652667169535371402012-06-06T10:11:00.000-07:002012-06-06T10:11:10.326-07:00AB Testing - ResultsIn <a href="http://fivelakesstudio.blogspot.com/2012/05/abtesting.html">Part 1</a> I talked about how we are adding interstitial ads into <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a>. We had been getting tips and suggestions on how to do this in a way that doesn't drive our users crazy. We decided to put together an AB Testing framework so we could learn from the results, and this is the results of that experiment.<div>
<br /></div>
<h3>
Interstitial Ad Providers Test</h3>
<div>
One of the tests we conducted was on interstitial Ad providers. We went with 2 different providers: <a href="http://www.chartboost.com/">ChartBoost</a> and <a href="http://www.playhaven.com/">PlayHaven</a>. These ads are displayed on launch of the application and half our users got ChartBoost and the other half got PlayHaven ads.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiM0A_2HVb_UGJJtNHqq7j63bPxd7SMF95C1tn4GqQh0UVdHofwJt913McS3o7QdvUgjvatKWkimdQ-o_rCrcEGMIx0YMNkThQDffnZbwPzLGdOBtaIGsHPF88NWc57Mx2QV3Jcb9dVobI/s1600/i3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiM0A_2HVb_UGJJtNHqq7j63bPxd7SMF95C1tn4GqQh0UVdHofwJt913McS3o7QdvUgjvatKWkimdQ-o_rCrcEGMIx0YMNkThQDffnZbwPzLGdOBtaIGsHPF88NWc57Mx2QV3Jcb9dVobI/s400/i3.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Ads Shown</td></tr>
</tbody></table>
<div>
Even though ChartBoost showed only 2% more ads, it generated 8% more clicks.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjo3PEnMXT97S8bZFGmH1cr4cXVH_WZ4-k7HuvEYHd22pMBH15AnqY5gpcnTQBm5VD3NOL9tDVspEMkwEsKQ_vvZ17UauDDSB2oSQtncLupPvKQxqp6ZLMbv3V-FKb8pR2N8up75dGaD4B/s1600/i2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjo3PEnMXT97S8bZFGmH1cr4cXVH_WZ4-k7HuvEYHd22pMBH15AnqY5gpcnTQBm5VD3NOL9tDVspEMkwEsKQ_vvZ17UauDDSB2oSQtncLupPvKQxqp6ZLMbv3V-FKb8pR2N8up75dGaD4B/s400/i2.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Ad Clicks</td></tr>
</tbody></table>
<div>
In addition, it turns out ChartBoost also produced significantly more revenue.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhECui_0xbui2o6FiJKDFM9yYXA9BP8r96JD4WYjByPO-LIpzwIYXve5vdf3eyAea8NEXmlL2fULN5YlJU_z6UMTuJ2-QTuIzPJROcF716a9RutKWvAFYdsY1HSqgVczmx0V5JEA_EhtjhN/s1600/i4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhECui_0xbui2o6FiJKDFM9yYXA9BP8r96JD4WYjByPO-LIpzwIYXve5vdf3eyAea8NEXmlL2fULN5YlJU_z6UMTuJ2-QTuIzPJROcF716a9RutKWvAFYdsY1HSqgVczmx0V5JEA_EhtjhN/s1600/i4.png" /></a></div>
<div>
<br /></div>
<div>
I plan on continuing to work with PlayHaven to see if we can improve the results. They have been great to work with, and I think they can do better.</div>
<div>
<br /></div>
<div>
The spike on the 29th was caused by two things at once. The first was a one day promotion on <a href="http://appsfire.com/">AppsFire</a>, and the second was we become more agressive on showing ads.</div>
<div>
<br /></div>
<h3>
Agressive, Normal, or Lax Ads</h3>
<div>
Another experiment we wanted to run was to determine how often we should show ads. We really didn't want to piss off our customers, and we weren't sure what the reaction would be. It's rather difficult introducing ads into a product that didn't have any ads to begin with.</div>
<div>
<br /></div>
<div>
We tested 3 different configurations: Agressive, Lax, and Normal. Each configuration had about the same level of distribution.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbE2jGXrQBu0ONlFaxDy1zS8Tu2yyjrTEemGAq8tTmTa0iyFDc5w6vL50fAAwwOmNK1uMoFFzvjlDYnD3-V4e2uixWweYtXvPwaN3tFj-MEaPV6nOf0gmV6jWQemCfmUYieIdu6pbcEXLE/s1600/i6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbE2jGXrQBu0ONlFaxDy1zS8Tu2yyjrTEemGAq8tTmTa0iyFDc5w6vL50fAAwwOmNK1uMoFFzvjlDYnD3-V4e2uixWweYtXvPwaN3tFj-MEaPV6nOf0gmV6jWQemCfmUYieIdu6pbcEXLE/s1600/i6.png" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
"Time Between Shows" is the minimum time that has to pass before we show another ad. For example, the agressive configuration won't show ads more then once every 5 minutes. In the Lax case, we where only showing an ad every day.</div>
<div>
<br /></div>
<div>
We also didn't want the user's first experience in launching the app to be an ad. So we used a "Sessions Before Active" configuration. In the case of agressive, we require the app to have 2 sessions before showing an ad.</div>
<div>
<br /></div>
<div>
We then looked to see what effects this had on our app usage. The Lax time was the closet measure we had to no ads, and it basically matched what we had seen before introducing ads.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpD4mPjTRbv5w4XIOtPX7PAs68ThAlsjgTnjDF7MfihC49r9dUkwUrMFngHEWP7i5GpCFRoR-vSbwsBSP_NsYJIQ9Zh1kelQgoIS9SKc3Djr2yF2NOVlE0ctco0bNXDukdh6IM7Bv3fhMX/s1600/m1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpD4mPjTRbv5w4XIOtPX7PAs68ThAlsjgTnjDF7MfihC49r9dUkwUrMFngHEWP7i5GpCFRoR-vSbwsBSP_NsYJIQ9Zh1kelQgoIS9SKc3Djr2yF2NOVlE0ctco0bNXDukdh6IM7Bv3fhMX/s640/m1.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Time in App with Lax Ad </td></tr>
</tbody></table>
<br />
<div>
Our takeaway was that we weren't seeing a significant shift or loss of time spend in app. Actually, you could argue the time spent in app actually improved a little bit. </div>
<div>
<br /></div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDsqkzACF2I_BwoGA-tPpf9VhhkEKNK5bxB1slIqMO2F14MWboMwfwDonG8UfutKFdvJmn8DFHGEKr-psT5zud4zlP2EMrZuhvuMT-7IFIXOzNNBi4hpq6J-DS9nhft2YPMiohAqCdaNN_/s1600/m2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDsqkzACF2I_BwoGA-tPpf9VhhkEKNK5bxB1slIqMO2F14MWboMwfwDonG8UfutKFdvJmn8DFHGEKr-psT5zud4zlP2EMrZuhvuMT-7IFIXOzNNBi4hpq6J-DS9nhft2YPMiohAqCdaNN_/s640/m2.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Time in App with Normal Ad </td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><div style="text-align: left;">
We also found it interesting that there was no significant difference between Normal and Lax ads.</div>
<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieRXf6IzlMDK3uRu7mGqeBBbXuHcvdOGk1iU_2GsYGOTEzorxve-v575eaOveMW4eeNboNgcO_rex9Wj2X0yVexXJ6QYMXGzVk8yHcn-slVre-H083gBcHC1_TT9SbpgEEwKLNuVhzX4qJ/s1600/m3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieRXf6IzlMDK3uRu7mGqeBBbXuHcvdOGk1iU_2GsYGOTEzorxve-v575eaOveMW4eeNboNgcO_rex9Wj2X0yVexXJ6QYMXGzVk8yHcn-slVre-H083gBcHC1_TT9SbpgEEwKLNuVhzX4qJ/s640/m3.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Time in App with Agressive Ad</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
Our AB Test framework allows us to adjust tests daily. Using that capability, we pulled the Lax ads configuration on May 29th, and we may soon go to just showing Agressive Ads. The one thing holding us back is sessions end almost 50% of the time after seeing an interstitial add!!</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh1qteNHtxrpCNRBJPc5eTIG8a3lgs60Hzdq-Px3sZcAFAw8m9C_SceQUz2gJa5NR-GfRe8cWtNiKtT9dcVZXSNc3y31kFe9Y7WLAl-3Zg9kQptktzhvZq29rww_7kMVoYv8KZdCffE8qE/s1600/i7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh1qteNHtxrpCNRBJPc5eTIG8a3lgs60Hzdq-Px3sZcAFAw8m9C_SceQUz2gJa5NR-GfRe8cWtNiKtT9dcVZXSNc3y31kFe9Y7WLAl-3Zg9kQptktzhvZq29rww_7kMVoYv8KZdCffE8qE/s1600/i7.png" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
This is a bit concerning to us as we only do an InterstitialShow when a session starts. That means almost half our users are exiting the app right after they started the app. Unfortunately, flurry doesn't let us track this by event so I can't tell how it compares across ad vendors. I'm still not exactly sure what this really means for the app's performance as I haven't see it negatively effect the number of sessions or time spent in app.<br />
<br />
<h3>
Ad Feedback</h3>
<div>
We have had several negative responses to the ads. However, it hasn't negatively effected our overall star rating or time spent in app. Some of the complaints we received include:</div>
<div>
<ul>
<li>Too easy to miss click on the ad</li>
<li>Video Ad consuming download bandwidth not appreciated (we also use AdColony for video ads).</li>
<li>Ads being introduced in a paid for app. Picross HD use to be a paid app a long time ago.</li>
</ul>
<div>
That last one was interesting because we don't show ANY still ads if any puzzle pack has been purchased, and we never show ads in the paid puzzle packs. However, we show video ads in the "free" puzzle packs. We are going to change this so that if any puzzle pack has been purchased we won't show any ads. I think it was just too confusing for users the other way.</div>
</div>
<div>
<br /></div>
<h3>
Conclusion</h3>
<div>
This has been an exciting experiment. The data is telling us we should just go with agressive ads and use ChartBoost as our ad provider. I'm still not comfortable pulling the agressive switch as I want to hear from more customers, and PlayHaven has been such a good group of people to work with I would like to see if they can perform better.</div>
<div>
<br /></div>
<div>
If we can make this model work, we would like to add more ad supported content in Picross HD.</div>
<div>
<br /></div>
<div>
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear about your experiences with ads and A/B Testing. Also feel free to contact me if you would be interesting in finding out more about our iOS AB Test framework. </div>
<div>
<br /></div>
<div>
Thanks for reading and be sure to visit us at <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a>.</div>
<div>
<br /></div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com2tag:blogger.com,1999:blog-8061157626403355683.post-75054161093053548702012-05-21T10:15:00.002-07:002012-05-21T10:26:33.676-07:00Mobile Website (dudamobile.com)<div>
OMG. <a href="http://www.fivelakesstudio.com/">Five Lakes Studio</a> is a mobile casual game company, but we had no mobile website. What's even worse is a majority of our traffic is coming from mobile devices (surprise!!!):</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsFitkG0gDI7Ih0EWczn5xWbxOH6f0HqLGj2cP4OvJaFN_DEaW_MCheOflpX4ij8dK7c9OztMSOvszeWHaKaJ64KkDLZovahg55GXNcS_OcdgAgU-sho97hgYQfvOsG7miUH09Bry4SppS/s1600/mobile.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsFitkG0gDI7Ih0EWczn5xWbxOH6f0HqLGj2cP4OvJaFN_DEaW_MCheOflpX4ij8dK7c9OztMSOvszeWHaKaJ64KkDLZovahg55GXNcS_OcdgAgU-sho97hgYQfvOsG7miUH09Bry4SppS/s1600/mobile.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEUbyuFA_yYMX55omE_pmBUacOV1N62w8AERxzZb8LsvCqZFzIZckcIdcrV5NPLxFO36IT4Vg0dToy2i5M2gcbXyFoQjA9n8ppKOsAVhHuRsplFBMGMH2wEXPKI6zJ_xwz29p2VGlJygZ8/s1600/Mobile+Devices.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEUbyuFA_yYMX55omE_pmBUacOV1N62w8AERxzZb8LsvCqZFzIZckcIdcrV5NPLxFO36IT4Vg0dToy2i5M2gcbXyFoQjA9n8ppKOsAVhHuRsplFBMGMH2wEXPKI6zJ_xwz29p2VGlJygZ8/s1600/Mobile+Devices.png" /></a></div>
<br />
<div>
<h3>
<b>How did we get here?</b></h3>
</div>
<div>
We don't get much traffic to our website, and we don't want to spend a lot of time on it. We focus our business on our users and our apps. For example, we just integrated <a href="http://appsfire.com/appbooster">AppsFire's AppBooster SDK</a> into <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a> so users can contact us and we can communicate with them directly within the App. I plan on writing a blog post just about it. So far the results are looking promising. However, you have to have a website.</div>
<div>
<br /></div>
<div>
While we could hand code HTML, we ended up using iWeb. Our pages are mostly static, and we wanted something that was fast to create and gives us creative control (not ridged templates). When we first launched <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/Euchre_HD.html">Euchre HD</a> we had some user complaints because they didn't understand how to setup Game Center. I was able to quickly (minutes) create and post visual <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/Euchre_Invite_Friend.html">step by step instructions</a> on how to do this by using iWeb and <a href="http://www.techsmith.com/snagit.html">Snagit</a>. </div>
<div>
<br /></div>
<div>
The downside with iWeb is it doesn't help with the creation of a mobile website, and the HTML produced isn't well suited for mobile. Also, I'm not sure what the future of iWeb is going to be. I think it is an amazing tool and I wish Apple was doing more with it.</div>
<div>
<br /></div>
<div>
<h3>
<b>What are we to do?</b></h3>
</div>
<div>
I started searching for a mobile website creation tool. I ended up finding an interesting online/hosted solution from <a href="http://dudamobile.com/">dudamobile.com</a>. They have an ad supported model and a paid model ($9.00/month). The paid model also supports connecting to your domain so now we have <a href="http://m.fivelakesstudio.com/">m.fivelakesstudio.com</a>. <br />
<br /></div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-hezNX84RA-rNE8t2v5n6kcyZ3D7l5z0ryBVuFykyuGi2F3tg2x-jP9dcq-SLyZP4vF-ILZWuznBPFhWvktnRQmbGURElqwv0vj66RpukU4M43vvBVr-Ei0GXbAcs1bhIDRAgI2bTKNkF/s1600/desktop+screenshot.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-hezNX84RA-rNE8t2v5n6kcyZ3D7l5z0ryBVuFykyuGi2F3tg2x-jP9dcq-SLyZP4vF-ILZWuznBPFhWvktnRQmbGURElqwv0vj66RpukU4M43vvBVr-Ei0GXbAcs1bhIDRAgI2bTKNkF/s320/desktop+screenshot.png" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFJp8zvjREiP0G6LnAfTBL62B25OxrJvO2kFA_7JygeDzyW19KOYTztlQsxCbnzjmlDBG1xlhhLUTvpXG4hz2FccUikU9zxK7LBPjX5K2T6RwWLxJuLf0_Vf2JJOtdeOJ0AF9oPop_8lVT/s1600/mobile+screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFJp8zvjREiP0G6LnAfTBL62B25OxrJvO2kFA_7JygeDzyW19KOYTztlQsxCbnzjmlDBG1xlhhLUTvpXG4hz2FccUikU9zxK7LBPjX5K2T6RwWLxJuLf0_Vf2JJOtdeOJ0AF9oPop_8lVT/s320/mobile+screenshot.png" width="171" /></a></div>
<br /></div>
<div>
<h3>
Getting Started</h3>
</div>
<div>
Its very easy to get started. Dudamobile walks you through setting up a new site. You can pick from several themes. The nice thing is you aren't locked into a theme. During editing you can customize the page headers, footers, background, colors, layout, and so much more. <br />
<br />
You can interact directly with a preview of a page and choose from many highly customizable interesting drag and drop widgets:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoKv7Hz5PbPBz9LXmsYp9mhui4Vh2ocANfmeB8laf_yJ_LR3HLL08ZiVoa-xyYC6Gif7nZ6ZVHdUGJgmbn5Gx6CmNoWNGIkBHinpTwxWlBUUEZcPMcmPoFWzjXSu4alQrT1f5ivhqyC_u0/s1600/overview2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="590" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoKv7Hz5PbPBz9LXmsYp9mhui4Vh2ocANfmeB8laf_yJ_LR3HLL08ZiVoa-xyYC6Gif7nZ6ZVHdUGJgmbn5Gx6CmNoWNGIkBHinpTwxWlBUUEZcPMcmPoFWzjXSu4alQrT1f5ivhqyC_u0/s640/overview2.png" style="cursor: move;" width="640" /></a><br />
<div class="separator" style="clear: both; text-align: -webkit-auto;">
My favorite widget is the Image Slider. You can add up to 3 images in a slider style control. You can see it above in the preview (currently showing <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/Kento.html">Kento</a>). </div>
<div class="separator" style="clear: both; text-align: -webkit-auto;">
<br /></div>
<h3>
Page Import and Syncing</h3>
<div class="separator" style="clear: both; text-align: -webkit-auto;">
One of the nice things about dudamobile is that it can import and sync to your existing website. When you add a page, you can give it the URL to one of your existing pages. It will then important the page. I was surprised this even worked for iWeb sites. I did have to do some basic cleanup and reformatting on the imported content. It was mostly deleting extra stuff I didn't want in the mobile site.</div>
<br />
I haven't tried syncing content. Most of the content we have is fairly static so I turned it off. Plus I am doubtful syncing will work well with iWeb, but I might be surprised again.<br />
<br />
<h3>
Support</h3>
I was impressed with the dudamobile support staff. I had some issues getting the slider to work the way I wanted. They where very responsive and helpful.<br />
<br />
<h3>
Conclusion</h3>
It has only been live for about a week and so far I am pleased with how this turned out. I still need to setup redirects on all the web pages to redirect to the mobile website. Currently, only the main page has a redirect.<br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear how others have solved their mobile website needs.<br />
<br />
I hope this was useful. Please visit <a href="http://www.fivelakesstudio.com/">our site</a> and try out our games for iOS.<br />
<br /></div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com8tag:blogger.com,1999:blog-8061157626403355683.post-55698746600110997072012-05-08T11:25:00.000-07:002012-05-08T11:25:38.654-07:00ABTestingWe are looking at adding interstitial ads into <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a>. We have been talking to people on the subject trying to get tips and suggestions on how to do this in a way that doesn't drive our users crazy and yet allows us to gain some additional revenue that we can use to keep making our games better.<br />
<br />
One point that kept being made was to use AB Testing for figuring out how to optimize what we are trying to do. This of course can be applied to many more things then ads, but I finally had a real need to solve this ABTesting problem.<br />
<br />
<b>The Problem</b><br />
<br />
I wanted a simple ABTesting platform that would allow me to do the following:<br />
<br />
<ol>
<li>Test different variables</li>
<li>Change variables without have to republish the App</li>
<li>Track / Report on the results</li>
</ol>
<br />
<h4>
<b>Variables</b></h4>
<br />
We use a simple XML file to define the test cases we want to experiment with. Here is a simple example of the XML definition we use:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><ABTest> <br />
<testset name="AdTime"><br />
<casedef name="Normal" weight="33"/><br />
<casedef name="Agressive" weight="33"/><br />
<casedef name="Lax" weight="33"/><br />
<br />
<vardef key="minTimeBetweenInterstitials"><br />
<case name="Normal" value="10.0"/><br />
<case name="Agressive" value="5.0"/><br />
<case name="Lax" value="1440"/><br />
</vardef><br />
<br />
<vardef key="numStartsBeforeShowingInterstitials"><br />
<case name="Normal" value="4"/><br />
<case name="Agressive" value="2"/><br />
<case name="Lax" value="10"/><br />
</vardef><br />
</testset><br />
</ABTest></span> <br />
<br />
This was developed so that we could have multiple test sets and run multiple ABTests at the same time. The example above just defines a single test set.<br />
<br />
With a test set, we can define multiple test cases we want to evaluate and we can define a frequency or weighting used to determine the percentage of users/devices that should be assigned that test case. In addition, each test set can have multiple variables and each variable can have values for each test case.<br />
<br />
We wrote a simple objective-c class that manages the loading of the XML and provides a simple interface for reading variables from the ABTest.<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">@interface FLABTestManager : NSObject</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">+ (FLABTestManager *)defaultManager;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">- (void)activateABTest;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> - (NSString *)stringForKey:(NSString *)key </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> withDefaultValue:(NSString</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">*)defaultValue;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> - (int)intForKey:(NSString *)key withDefaultValue:(int)value;<br />
- (float)floatForKey:(NSString *)key withDefaultValue:(float)value;<br />
- (bool)boolForKey:(NSString *)key withDefaultValue:(bool)value;<br />
@end</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<div>
The XML file is included as a project resource and then within the apps delegate method <span style="font-family: 'Courier New', Courier, monospace;">applicationDidBecomeActive</span> you call <span style="font-family: 'Courier New', Courier, monospace;">activeABTest:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> - (void)applicationDidBecomeActive:(UIApplication *)application<br />
{<br />
..<br />
[[FLABTestManager defaultManager] activateABTest];<br />
..<br />
}</span></div>
<div>
<br />
Once activated, the App will randomly pick a test case by weight for each test set defined. It should be noted that once picked, the app will keep using the same test case even if the app quits. This effectively locks a device into a particular test. If the app is uninstalled and reinstalled a new test case may get chosen.<br />
<br />
We choose to only activate the test cases from within <span style="font-family: 'Courier New', Courier, monospace;">applicationDidBecomeActive</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span>so we only activate once per session. This is because it is possible to have a different configuration chosen during activation (see Changing Tests) and for reporting/tracking purposes we don't want to mix test cases (see Tracking/Reporting).<br />
<br />
In order to read a variable under test, simple accessors methods are provided. For example: If we where configured for Agressive Ad display and we had the XML definition above then the variable <span style="font-family: 'Courier New', Courier, monospace;">minTimeBetweenInterstitials</span> would return <span style="font-family: 'Courier New', Courier, monospace;">"5.0"</span>:<br />
<div class="p1">
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">[[FLABTestManager defaultManager] floatForKey:@"minTimeBetweenInterstitials"</span></div>
<div class="p1">
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> withDefaultValue:@"10.0"];</span></div>
<br />We supply a default value for the case when the test hasn't been activated or if there was a problem determining the value.</div>
<div>
<br /></div>
<div>
<h4>
Changing Tests</h4>
<div>
<br /></div>
We wanted the ability to change tests without having to republish the App. This allows us to refine settings as we learn. In order to do this, a copy of the XML is stored and retrieved via a GoogleAppEngine service.<br /><br />When an app doesn't have an AB Test loaded, it just uses the built in XML definition and a request is made to the web service for an updated version. If there is an updated version, it will be downloaded and kept ready for the next ABTest activation. <br />
<br />
When a new, downloaded, version of the ABTests are found the app will adjust to the new values accordingly. For example if the apps current test case is no longer available in the XML definition, it will just pick a new test case.<br />
<br />
<h4>
<b>Tracking / Reporting</b></h4>
<br />
Whenever <span style="font-family: 'Courier New', Courier, monospace;">activateABTest</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span>is called we log events to Flurry for the active test cases. For example if the above XML definition is used and the device chooses <span style="font-family: 'Courier New', Courier, monospace;">Agressive</span> for <span style="font-family: 'Courier New', Courier, monospace;">AdTime</span> then the following two events would be logged:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> AdTime <== with parameter of Agressive<br />
AdTime.Agressive</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />
</span>This is enough information to allow us to create a segmentation on "<span style="font-family: 'Courier New', Courier, monospace;">AdTime.</span><span style="font-family: 'Courier New', Courier, monospace;">Agressive</span>" so we can see how it compares with other tests. We also log "<span style="font-family: 'Courier New', Courier, monospace;">AdTime</span>" as an event by itself with the parameter set to the test case picked so we can validate the distribution of test cases.<br />
<br />
<h4>
<b>Conclusion</b></h4>
<br />
We are still finishing testing on this new framework and we hope to submit to the AppStore next week. I think this has some nice potential to allow us to do more ABTesting on the work we do in order to improve the user experience of our products. I will report back on our findings.<br />
<br />
If you would be interesting in using this framework, just let me know. I can't really hook you up with the GoogleAppEngine side of things, but I would be happy to share what I can on the iOS side.<br />
<br />
Please feel free to follow me on twitter at <a href="http://twitter.com/#!/fivelakesstudio">@fivelakesstudio</a>. I would love to hear how others have solved this AB Testing issue.<br />
<br />
I hope this was useful. Please try out <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a> and our other puzzle games for iOS.<br />
<br />
<br /></div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0New Hudson, Lyon Township, MI 48165, USA42.5108667 -83.615494742.4991617 -83.6352357 42.5225717 -83.5957537tag:blogger.com,1999:blog-8061157626403355683.post-19228025525858241632012-04-09T10:13:00.000-07:002013-04-07T06:48:23.264-07:00Push Notifications and Urban AirshipI have been considering putting Push Notifications into <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a> for some time now. This weekend, I decided to take the plunge and give it a try. I will try to cover some of the hiccups and things that I have been trying.<br />
<br />
<b>Why Push Notifications</b><br />
<br />
Ken and I aren't very good at the marketing side of things, but everyone I talk with about marketing asks if we use push notifications. I finally decided there must be something to this so let's give it a try. <br />
<br />
There are a couple of uses for push notifications that I would like to try:<br />
<ol><li>Notify Picross HD users of new puzzle packs being available. We plan on releasing one new puzzle pack a month, and we would like to notify users when they are available.</li>
<li>Notify users about our other puzzle games. This one makes me a bit nervous as I don't wont to spam our users, but I also think many Picross HD users would also enjoy some of our other puzzle games. I'm figuring to give it a try and see what kind of response we get.</li>
</ol>I would be interested in hearing what you use push notifications for or what you like or dislike about push notification uses.<br />
<br />
<b>Urban Airship</b><br />
<br />
One thing about push notifications is that you need a service to bridge between you and Apple's push notifications servers. I considered setting up my own server for this, but I decided to go with <a href="http://urbanairship.com/">Urban Airship</a> for now. For the level of service I need, their service would be "free" and seemed to be the easiest way to get started with Push Notifications. <br />
<br />
<b>Getting Started</b><br />
<br />
Urban Airship has a good <a href="https://docs.urbanairship.com/display/DOCS/Getting+Started:+iOS:+Push">getting started guide for push notification</a>. However, I do have a couple of tips.<br />
<blockquote class="tr_bq"><b>Tip 1: </b>You will need to regenerate your provisioning profiles after you enable push notifications for your existing App Id. If you don't, you will get an error when trying to registerForRemoteNotificationTypes as the provisioning profiles needs to be configured for push notifications.</blockquote><blockquote class="tr_bq"><b>Tip 2</b>: The getting started guide walks through the steps of using a AirshipConfig.plist to switch between production and development for the notification servers. I don't like this technique as it is too error prone. It's too easy to forget how you have it configured. They suggest using build scripts to manipulate this file, but I don't like that from a maintenance perspective plus I didn't find a quick example of how to do this. Fortunately, you can do this programmatically instead of using the AirshipConfig.plist. Here is an example of how <a href="https://support.urbanairship.com/customer/portal/questions/116967-setting-the-key-and-secret-through-code">taken from the Urban Airship forums</a> (but modified a bit by me). </blockquote><!-- HTML generated using hilite.me --><br />
<div style="background: #f8f8f8; border-width: .1em .1em .1em .8em; border: solid gray; font-size: small; overflow: auto; padding: .2em .6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: green; font-weight: bold;">-</span> (<span style="color: #b00040;">void</span>)<span style="color: blue;">setupUrbanAirshipPushNotificationsWithLaunchOptions:</span>(NSDictionary <span style="color: #666666;">*</span>)<span style="color: #19177c;">launchOptions</span>
{
<span style="color: #408080; font-style: italic;">// Set passed in launch options</span>
NSMutableDictionary <span style="color: #666666;">*</span>takeOffOptions <span style="color: #666666;">=</span> [[NSMutableDictionary alloc] init];
[takeOffOptions <span style="color: #a0a000;">setValue:</span>launchOptions <span style="color: #a0a000;">forKey:</span>UAirshipTakeOffOptionsLaunchOptionsKey];
<span style="color: #408080; font-style: italic;">// Create and set dictionary for AirshipConfig values</span>
NSMutableDictionary <span style="color: #666666;">*</span>airshipConfigOptions <span style="color: #666666;">=</span> [[NSMutableDictionary alloc] init];
[takeOffOptions <span style="color: #a0a000;">setValue:</span>airshipConfigOptions <span style="color: #a0a000;">forKey:</span>UAirshipTakeOffOptionsAirshipConfigKey];
[airshipConfigOptions <span style="color: #a0a000;">setValue:</span><span style="color: #ba2121;">@"Application Key"</span> <span style="color: #a0a000;">forKey:</span><span style="color: #ba2121;">@"DEVELOPMENT_APP_KEY"</span>];
[airshipConfigOptions <span style="color: #a0a000;">setValue:</span><span style="color: #ba2121;">@"Application Secret"</span> <span style="color: #a0a000;">forKey:</span><span style="color: #ba2121;">@"DEVELOPMENT_APP_SECRET"</span>];
[airshipConfigOptions <span style="color: #a0a000;">setValue:</span><span style="color: #ba2121;">@"Application Key"</span> <span style="color: #a0a000;">forKey:</span><span style="color: #ba2121;">@"PRODUCTION_APP_KEY"</span>];
[airshipConfigOptions <span style="color: #a0a000;">setValue:</span><span style="color: #ba2121;">@"Application Secret"</span> <span style="color: #a0a000;">forKey:</span><span style="color: #ba2121;">@"PRODUCTION_APP_SECRET"</span>];
[UAirship <span style="color: #a0a000;">setLogging:</span>YES];
<span style="color: #bc7a00;"> #ifdef PRODUCTION_PUSH_NOTIFICATIONS</span>
[airshipConfigOptions <span style="color: #a0a000;">setValue:</span><span style="color: #ba2121;">@"YES"</span> <span style="color: #a0a000;">forKey:</span><span style="color: #ba2121;">@"APP_STORE_OR_AD_HOC_BUILD"</span>];
<span style="color: #bc7a00;"> #else</span>
<span style="color: #bc7a00;"> #warning PUSH NOTIFICATIONS SET TO DEVELOPMENT</span>
[airshipConfigOptions <span style="color: #a0a000;">setValue:</span><span style="color: #ba2121;">@"NO"</span> <span style="color: #a0a000;">forKey:</span><span style="color: #ba2121;">@"APP_STORE_OR_AD_HOC_BUILD"</span>];
<span style="color: #bc7a00;"> #endif</span>
[UAirship <span style="color: #a0a000;">takeOff:</span>takeOffOptions];
[[UAPush shared] <span style="color: #a0a000;">setDelegate:</span>self];
[[UAPush shared] resetBadge]; <span style="color: #408080; font-style: italic;">//zero badge on startup</span>
[[UAPush shared] <span style="color: #a0a000;">registerForRemoteNotificationTypes:</span>(UIRemoteNotificationTypeBadge <span style="color: #666666;">|</span>
UIRemoteNotificationTypeSound <span style="color: #666666;">|</span>
UIRemoteNotificationTypeAlert)];
}
</pre></div><br />
This can be called from within application:didFinishLaunchingWithOptions.<br />
<blockquote class="tr_bq"><b>Tip 3</b>: In order to test notifications you can use the command line utility curl. However, I ended up using an app called <a href="http://itunes.apple.com/us/app/rested-simple-http-requests/id421879749?mt=12">RESTed</a> available on the Mac App Store. Its UI could be a bit better, but I was able to edit the Push payload easier in RESTed then trying to do it on the command line. I also found that with curl the payload didn't like being split on multiple lines using line continuations.</blockquote><blockquote class="tr_bq"><b>Tip 4</b>: Add the application:didFailToRegisterForRemoteNotificationsWithError to your app delegate. The guide doesn't instruct you to do this, but if something goes wrong during device registration, its very handle to have this method log the error information.</blockquote><br />
<b>Processing Push Notifications</b><br />
<br />
When processing push notifications it's up to the App to figure out what to do with the notifications (including showing them). The UAPush class from Urban Airship helps manage push notifications by handling things like badges and parsing of push notifications. Setting up UAPush is easy, as you can see in the example code above. <br />
<br />
In order for UAPush to parse the notifications, you need to pass them to UAPush via its handleNotification:applicationState method.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiopt2IGZSC-kbkqeoF-QbTUk1axVRr8YkgFRXndJwu66phk1krkQnIfPh0uC2ZNKi1EhBkSQUlhaXgi4GxbOxe3oe8zSIR82-sdl3Fqv2Xd-eebl1BkWhm5p1HnjxN9RF-Pv-wsVmiqNAo/s1600/Notification.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiopt2IGZSC-kbkqeoF-QbTUk1axVRr8YkgFRXndJwu66phk1krkQnIfPh0uC2ZNKi1EhBkSQUlhaXgi4GxbOxe3oe8zSIR82-sdl3Fqv2Xd-eebl1BkWhm5p1HnjxN9RF-Pv-wsVmiqNAo/s1600/Notification.png" /></a></div><br />
This was taken from example code for the UAPush. However, I modified it to remove the applicationState check. application:didReceiveRemoteNotification can be called before the application has been made active. However, I still want to display an alert even if we are becoming active. From what I can tell the method only gets called while the application is being "launch" or "restored", it doesn't get called while the app is backgrounded. However, if handleNotification:applicationState is called with an inactive state, it won't call its delegate parsing methods. Which isn't what I wanted. I want the App to display a notification if the notification is clicked on outside the app.<br />
<br />
I still looking into understanding the implications of this, but I think for my purposes (of displaying an alert) it is fine.<br />
<br />
<b>Localization Implications</b><br />
<br />
Picross HD is localized into 5 languages so when sending notifications, I would like them to be localized. However, I haven't figured out how to send a localized push alert (see "loc-key") without having the text pre-localized and stored in the application's Localizable.strings file(s). <br />
<br />
While you can send custom push notifications that are localized, iOS won't know how to display them. For notifications within the App that isn't an issue because the App has control of that, but when the app is in a background iOS can only display "toast" messages for types it knows about such as alerts.<br />
<br />
This means you have to predetermine the messages you might want to send if you want them localized. You can also supply message arguments to fill in placeholders in the message such as %@. However, I don't believe the arguments are localized. <br />
<br />
<b>Conclusion</b><br />
<br />
I'm still working on the implementation and trying to figure out the types of messages and workflows I want to do. For example, if I do an announcement of a new puzzle pack some people may be on the old version that doesn't have that puzzle pack available and some may be on the new version that has the new puzzle pack. In the first case, I may want to provide an option for the use to update to the latest version, in the later case I may want to take them to the new puzzle pack so they can try it out.<br />
<br />
I hope this was useful. Please try out <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a> and our other puzzle games for iOS.<br />
<br />
- TodTodhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com4tag:blogger.com,1999:blog-8061157626403355683.post-37841172434669861852012-03-26T08:22:00.003-07:002012-03-26T11:29:33.659-07:00Picross HD Localization - Part IIAt a <a href="http://mobilemondayannarbor.org/">Mobile Mondays</a> meeting in Ann Arbor, Michael Antaran founder of <a href="https://www.facebook.com/pages/Marvel-Apps-LLC/169995083025646">Marvel Apps</a>, was talking about the benefits of localizing AppStore Apps. That was enough to inspire me to give it a try.<br />
<br />
In the <a href="http://fivelakesstudio.blogspot.com/2012/02/picross-hd-localization.html">first part</a>, I explained that we decided to localize <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a> into three languages: German, French, and Japanese along with some of the lessons we had learned. Now that the localized versions have been in the AppStore for about a month, I thought it would be good to share the results along with some other interesting tidbits we learned.<br />
<br />
<b>German & French</b><br />
<br />
We didn't see any positive impact to new user growth for localizing in German.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju1G7JFv6x5JBnTecusHLTRDd5Av77yaHqYzlv_9NpbrLtfmbCRVrm3uVwC-6nuSl27o7LUwizwJ_HPiDhiN-ST7KGkNT4BqfhiFzsjMh-w3t8U5FI4VfHJtMlz2x9LZGOec8Hol2p7t4K/s1600/German.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="354" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju1G7JFv6x5JBnTecusHLTRDd5Av77yaHqYzlv_9NpbrLtfmbCRVrm3uVwC-6nuSl27o7LUwizwJ_HPiDhiN-ST7KGkNT4BqfhiFzsjMh-w3t8U5FI4VfHJtMlz2x9LZGOec8Hol2p7t4K/s640/German.png" width="640" /></a></div>
<br />
We did see a short term spike in new users for the French version, but after a few days it returned to its normal trends.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6VEKL-26K7RcZKV8J_iyu0B9tCEEINxp0K_woROLRe1HpVz-95TBJETNyuMz4THcqAW_3lF9fnhXexQ21k3sQM17Qvsc0TCvscUDW4-i4u4S3RRFY5RqL9jy9onj4laWZZwocXM77LY3j/s1600/French.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6VEKL-26K7RcZKV8J_iyu0B9tCEEINxp0K_woROLRe1HpVz-95TBJETNyuMz4THcqAW_3lF9fnhXexQ21k3sQM17Qvsc0TCvscUDW4-i4u4S3RRFY5RqL9jy9onj4laWZZwocXM77LY3j/s640/French.png" width="640" /></a></div>
<br />
<br />
I expected to see bigger results for localizing Picross HD into German and French. I would love to hear back on what other people have experienced when localizing into German and French. Are these results typical? Is English just not an issue in those countries for people using iOS devices for puzzle style gaming?<br />
<br />
<b>Japanese</b><br />
<br />
We have had great growth in Japan sense we localized. Japanese New User acquisition is allmost an order of magnitude greater then all other locals combined. And it continues to grow. I want to say thank you to all our new Japanese users.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXWh-ONL_mtTibYWqywIwxzw1VLeF4sVRPEb9r1HrGwLIAr1jE3CuZDDDgzJaPG5M1kbFRVe40kq8xd9NprVqfH5MXlHy_Q18nEj87xYS-kQ1fZHxlMhbtkmKGm01fnRkRw21xqToQtSVV/s1600/Japanese.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXWh-ONL_mtTibYWqywIwxzw1VLeF4sVRPEb9r1HrGwLIAr1jE3CuZDDDgzJaPG5M1kbFRVe40kq8xd9NprVqfH5MXlHy_Q18nEj87xYS-kQ1fZHxlMhbtkmKGm01fnRkRw21xqToQtSVV/s640/Japanese.png" width="640" /></a></div>
<br />
Why the great growth? Well for starters, I believe Picross as a game style is better know in Japan then it is in other parts of the world. We also totally overhauled the Keywords for Japanese. We used keywords that would be meaningfully for the Japanese people. Even with all that, this totally exceeded my expectations.<br />
<br />
<b>iPhone vs iPad</b><br />
<br />
Almost all of our games are Universal apps, and we usually see close to 50/50 spread across iPhone and iPad usage. For example, in Germany about 55% of Picross HD sessions are run on an iPad. However, in Japan that number is about 4%. We where surprised about that difference. What have other people seen for iPhone vs iPad usage of their apps in different locals?<br />
<br />
<b>What's Next</b><br />
<br />
We want to continue to experiment with different locals. The next version of Picross HD, which is pending Apple approval, will include support for Korean. We took a similar approach to Korean as we did for Japanese by providing local specific keywords so that should be interesting.<br />
<br />
We have also been working on some major updates to Picross HD given its new found growth. All the puzzles in the next version will have unique solutions and be solvable by logic. That should help address two of the big feedback items we received from our Japanese users.<br />
<br />
We are also looking at how to make the iPhone version even better. Much of our focus has been on the iPad version, but with this much usage on the iPhone we are going to have to pay even more attention to the iPhone version.<br />
<br />
Be sure to give <a href="http://itunes.apple.com/us/app/picross-hd/id381551512?mt=8">Picross HD</a> a try and let us know what you think. It's a free download. :)<br />
<br />
Thanks,<br />
Tod and Ken<br />
Five Lakes Studio, LLC<br />
<div>
<br /></div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com1tag:blogger.com,1999:blog-8061157626403355683.post-14899991624105706552012-02-27T06:00:00.004-08:002012-03-26T12:29:33.840-07:00Picross HD LocalizationAt a <a href="http://mobilemondayannarbor.org/">Mobile Mondays</a> meeting in Ann Arbor, Michael Antaran founder of <a href="https://www.facebook.com/pages/Marvel-Apps-LLC/169995083025646">Marvel Apps</a>, was talking about the benefits of localizing AppStore Apps. That was enough to inspire me to give it a try. I spent the last week localizing <a href="http://www.fivelakesstudio.com/Five_Lakes_Studio/PicrossHD.html">Picross HD</a>, our best revenue generating App so far, and I thought I would share my experiences thus far.<br />
<br />
<b>Languages</b><br />
<br />
Using some metrics and based on the appeal of Picross HD, the first thing I decided was to localize in 3 languages: German, French, and Japanese. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV3DF746Ox4FL_IwzKWRSVbydHgBYM7NvY-rDaeuuv-Bv1cN5yj2WdcbbgNRYDj11ghRD0UYgiO6wQonTXF90zXMWOkHS0GsC7-lmEWRtcNHTCXm2KnurOVAjprpJCarCtbwYibrVbqLHC/s1600/2012-02-21_2257.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV3DF746Ox4FL_IwzKWRSVbydHgBYM7NvY-rDaeuuv-Bv1cN5yj2WdcbbgNRYDj11ghRD0UYgiO6wQonTXF90zXMWOkHS0GsC7-lmEWRtcNHTCXm2KnurOVAjprpJCarCtbwYibrVbqLHC/s320/2012-02-21_2257.png" width="320" /></a></div>
<br />
<b>Contractors</b><br />
<br />
We used <a href="https://www.odesk.com/">odesk</a> to find the people to do the localization and that has been a very good experience. It was really easy to find people to do French and German. It was a little harder finding someone to do a good job on Japanese. However, everyone we ended up working with was responsive, quick, affordable, offered good advice, and did an all around great job. It took about a week to get all 3 translations completed.<br />
<div>
<br /></div>
<div>
<b>How to Localize</b></div>
<br />
Before I connected with the odesk people, I first needed to figure out how we wanted to approach the actual localization and how to get the strings extracted. A great reference for this is on Ray Wenderlich's blog in a <a href="http://www.raywenderlich.com/2876/how-to-localize-an-iphone-app-tutorial">Localization article by Sean Berry</a>. I wanted to keep the localization really simple as I didn't want the odesk people to have to have special tools such as resource editors. So I put all the strings into a few files I could send to them:<br />
<ul>
<li>description.rtf - Containing the app store description</li>
<li>help.rtf - Text for the app help</li>
<li>Localizable.strings - App strings, Game Center Leader board Strings, and in-app store strings</li>
</ul>
I put some extra strings in the Localizable.strings even through they aren't directly used by the App such as the Game Center Strings and in-app store strings. This just made it easier to communicate with odesk and gave me a good place to manage the strings over time.<br />
<br />
I gathered strings from a few different places:<br />
<ul>
<li>From XML puzzle files - Using a XSLT transform (this was a majority of the strings). The name of each puzzle needed to be localized and we have over 400 puzzles in Picross HD.</li>
<li>From each XIB (resource) file - I did this manually. I didn't want the contractors to have to deal with a resource editor so I just manually added the UILabel and UIButton text into the Localizable.strings file.</li>
<li>Look for hard coded strings in the app and added the NSLocalizedString(@"english text", nil) macro for each string needing translation.</li>
</ul>
Strings coming from a resource file won't automatically lookup their translation via Localizable.strings. The resource files assume you will localize each resource file separately which I didn't want to do. So I just added some simple code to the UIViewControllers of each xib that needed to be localized:<br />
<br />
<pre class="brush:python">- (void)viewDidLoad
{
[super viewDidLoad];
// Localize the labels in this view
//
for( id foundView in self.rateThisPuzzleButtonView.subviews )
{
if( [foundView isKindOfClass:[UILabel class]] )
{
UILabel *label = foundView;
label.text = NSLocalizedString( label.text, nil );
}
}
}
</pre>
<br />
In order to do the buttons, I decided to just do those manually as I didn't have that many buttons to do:<br />
<pre class="brush:python"> [self.puzzleSuccessTryAgainButton setTitle:NSLocalizedString([self.puzzleSuccessTryAgainButton titleForState:UIControlStateNormal],nil) forState:UIControlStateNormal];
[self.puzzleSuccessNextButton setTitle:NSLocalizedString([self.puzzleSuccessNextButton titleForState:UIControlStateNormal],nil) forState:UIControlStateNormal];
</pre>
<br />
I also had to adjust the font and/or button sizes in order to accommodate the length of the German text. This was a little tricky given how some of our buttons worked. I ended up doing a <a href="http://stackoverflow.com/questions/2451223/uibutton-how-to-center-an-image-and-a-text-using-imageedgeinsets-and-titleedgei/9288020#9288020">StackOverflow</a> posting once I figured out how to solve button text wrapping issues.<br />
<br />
<b>Lessons Learned</b><br />
<br />
Doing three languages at once was a bit much for the first time trying to localize an app. It would have been better to start with just one language. There where several mistakes I made that required me to add more work on the localization teams. Every time I did this, I had to communicate back with 3 different people and it was just more work then getting it right the first time. The types of mistakes I made where:<br />
<br />
<ul>
<li>When I sent the strings to the localization teams I didn't realize I was missing about 50 puzzles. The XSLT transform I wrote missed some puzzles.</li>
<li>I should have sent screenshots to the localization team up front as they didn't have enough context to do some of the translations. They ended up doing some redo work once I sent them the screenshots.</li>
<li>I often use images for the help screens, but I was missing the original layered image for one of the help screens. I ended up spending a few hours recreating a help screen so I could replace the text easily. Save your original layered artwork (especially if it has text in it).</li>
<li>Images with text == pain. I knew this before, but zero thought had went into the idea we might localize this App when we first wrote it over a year ago. To help this, I wrote some code to dynamically load a localized version of an image file based on the active language.</li>
</ul>
<div>
Overall, this was a very easy effort. It only took about a week of my part-time schedule to go from nothing localized to having three languages and ready for posting to the AppStore. Apple's tools and handling of fonts and languages works great.</div>
<b><br /></b><br />
<b>Next Steps</b><br />
<br />
This just got released to the AppStore so wish us luck. I will report back when we know more how this experiment went. Ken and I are hoping to see a noticeable uptick and we hope more people enjoy Picross HD in their native language.<br />
<br />
Be sure to give <a href="http://itunes.apple.com/us/app/picross-hd/id381551512?mt=8">Picross HD</a> a try and let us know what you think.<br />
<br />
Thanks,<br />
Tod and Ken<br />
Five Lakes Studio, LLC<br />
<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com2tag:blogger.com,1999:blog-8061157626403355683.post-79292262689629963142012-02-09T19:16:00.001-08:002012-02-25T07:54:42.145-08:00Michigan Swimmers Using English Channel Record Attempt to Raise Money for ALS Cure<div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
<span style="background-color: white; color: #111111; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 13px; line-height: 20px; text-align: -webkit-auto;">Six Michigan women are training to break the world record for fastest two-way relay swim crossing of the English Channel to raise money to find a cure for ALS, or Lou Gehrig’s disease.</span></div>
<div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
<span style="background-color: white; color: #111111; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 13px; line-height: 20px; text-align: -webkit-auto;"><br /></span></div>
<a href="http://www.ahealthiermichigan.org/2012/02/09/michigan-swimmers-using-english-channel-record-attempt-to-raise-money-for-als-cure/#.TzSK_3u6eTA.blogger" style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">Michigan Swimmers Using English Channel Record Attempt to Raise Money for ALS Cure</a><br />
<div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
<br /></div>
<div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
Ken and I put together a special version of <a href="http://itunes.apple.com/us/app/kento-als/id471098684?mt=8">Kento</a> to help support their effort and this good cause.</div>
<div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
<br /></div>
<div>
<a href="http://itunes.apple.com/us/app/kento-als/id471098684?mt=8">Kento ALS App</a></div>
<div>
<br /></div>
<div>
<br /></div>Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0tag:blogger.com,1999:blog-8061157626403355683.post-9149457276100749012011-11-21T05:00:00.000-08:002016-07-28T05:44:15.599-07:00Game Art for the Artistically Challenged (Part 2)<div>
Hello again, this is Ken Vadella blogging for <a href="http://fivelakesstudio.com/">Five Lakes Studio, LLC</a> (FLS).</div>
<div>
<br /></div>
<div>
In my last article on the subject of <a href="http://fivelakesstudio.blogspot.com/2011/10/game-art-for-artistically-challenged.html">Game Art</a> I discussed the FLS strategy for acquiring artwork for our iOS projects. A reader of this posting (plicatibu) provided, what looks to be, a very valuable website for hiring artists to produce custom artwork at reasonable prices - thanks plicatibu. The site is called <a href="https://www.odesk.com/">oDesk</a> and though we have not tried to use it as of yet we plan to give it a shot in the near future. Check it out.</div>
<div>
<br /></div>
<div>
This month I would like to discuss the editing tools we use to turn our art findings into usable game components. Let me start with a small sidebar discussing how we choose tools for our efforts. The following list summarizes our evaluation technique. The list is in order of importance.</div>
<div>
<br />
<b><span class="Apple-style-span" style="font-size: small;">Costs</span></b><br />
We don't want to spend an arm and a leg for image editing tools.<br />
<br /></div>
<div>
<b><span class="Apple-style-span" style="font-size: small;">Features</span></b></div>
<div>
A text editor with a limited feature set isn't very useful to us. Here are some of the items we look for in our image editing tools:<br />
<ul>
<li>File Format Support - PNG, JPG, etc.</li>
<li>Layers - No layers, no tool. It's really that simple for us. We love layers for image editing and find it nearly impossible to live without this feature.</li>
<li>History - No undo/redo, why bother. See above.</li>
<li>Effects - Blurs, distortion, noise, embossing, etc.</li>
</ul>
<b><span class="Apple-style-span" style="font-size: small;">Simplicity</span></b></div>
<div>
What is simple to some is difficult for others. Tod and I are not new to image editing but we are also far from experts; this is not a task that we do everyday so we look for easy to use tools.</div>
<div>
<br />
<b><span class="Apple-style-span" style="font-size: small;">Availability</span></b></div>
<div>
A product that runs on multiple platforms is a plus but not a show-stopper. We have access to many brands of computers that run many different operating systems. If a tool meets our other criteria then we won't rule it out just because it doesn't work on a Mac OS.</div>
<div>
<br /></div>
<div>
<b><span class="Apple-style-span" style="font-size: small;">The Gold Standard</span></b></div>
<div>
For us Adobe Photoshop CS5 is the gold standard of image editing but it does not fit the shoe string budget of a startup company like FLS. Don't get me wrong, if we didn't have alternatives we would pay the money and acquire copies of CS5. But, we do have alternatives that suit our needs very well and cost <b>significantly</b> less money to acquire. </div>
<div>
<br /></div>
<div>
<b><span class="Apple-style-span" style="font-size: small;">The List</span></b></div>
<div>
Without further ado, let's move to that list. These are the tools that we use for our image editing tasks. This list is arranged in order of preference as it relates to FLS.</div>
<div>
<br /></div>
<div>
<a href="http://www.getpaint.net/"><b><span class="Apple-style-span" style="font-size: small;">Paint.NET</span></b></a></div>
<div>
My preferred application for image editing. This may be sacrilegious to some because it does not run on a Mac OS. But, as I mentioned above, we have access to many brands of computers running many different operating systems and this tool has a lot of positive attributes:</div>
<div>
<ul>
<li>It's very easy to use.</li>
<li>It performs well.</li>
<li>It's very stable - we can't remember the last time it crashed.</li>
<li>It fits all of the criteria cited above with the exception of Availability.</li>
<li>It is 100% free. Yes, free.</li>
</ul>
<div>
<a href="http://www.pixelmator.com/"><b>Pixelmator</b></a></div>
<div>
Tod's preferred editor and for those on Mac OS. It exhibits many of the positives cited above for Paint.NET. Some other positive things that can be said about Pixelmator include:</div>
<div>
<ul>
<li>Reasonable pricing. It's not free but you won't need to do much more than skip a restaurant dinner with your significant other to save enough money to buy a copy.</li>
<li>It performs well - it's fast; really fast.</li>
<li>It reads native Adobe Photoshop files relatively well - Paint.NET does not do this.</li>
</ul>
</div>
<div>
But it comes with some minuses as well:</div>
<div>
<ul>
<li>It lacks basic drawing tools. This seems like a major oversight. I have heard that newer versions of Pixelmator will support drawing tools.</li>
<li>It lacks that ease of use inherent to Paint.NET. It's not difficult to use, but it isn't as easy to use as Paint.NET.</li>
</ul>
Still, it is a wonderful editor for the money.</div>
<div>
<br /></div>
<div>
<b><a href="http://pixlr.com/">pixlr</a></b></div>
<div>
Pixlr is an oddity in this list. It's not a product that you put on your machine and run. Rather, it runs in the context of a web browser. It works surprisingly well and is very full-featured. But, the whole edit-in-browser experience feels, somehow, too crammed for space and for this reason we tend to use it less than the other editors mentioned above. Still, it's free, cross-platform and powerful. What more could you really ask for?</div>
<br />
<a href="http://www.gimp.org/">The GIMP</a></div>
<div>
You can say many positive things about GIMP:</div>
<div>
<ul>
<li>It is very powerful.</li>
<li>It's free. Yes, free.</li>
<li>It's cross-platofrm.</li>
</ul>
It's everything that Paint.NET is and more. And yet, we don't use it that often. We use it less than any other editor in this article. Why? Because it's lacking in simplicity and user-friendliness. At least, we feel this way about it. Maybe we are just not that bright. Give it a try though, you might find otherwise.</div>
<div>
<br />
<a href="http://www.techsmith.com/snagit.html">Snagit</a><br />
We also use Snagit to take screenshots and do basic image editing to help communicate with our customers and each other. Snagit gets heavily used for support, it's so much easier and clearer sending a picture then a bunch of text. Snagit does a great job of taking screenshots of the iOS simulator, saving and tagging them, and allowing awesome markup. It is affordable and works on both Mac and PC. I should say that Tod works at TechSmith the makers of Snagit.<br />
<br /></div>
<div>
<b><span class="Apple-style-span" style="font-size: small;">Final Comments</span></b></div>
<div>
That's it for this Blog entry. I hope you find one or more of these editors to your liking.</div>
<div>
<br /></div>
<div>
In a future Blog entry I will discuss some additional tools that we use to make our art assets even better. I'd also be interested in what image editors you use in your development efforts. It never hurts to evaluate new products recommended by others.</div>
<div>
<br /></div>
<div>
Thanks for reading.</div>
<div>
<br /></div>
<div>
Ken</div>
<div>
<br />
<br />
PS (7/28/2016): One thing that was missing from this review was some web based photo editors.<br />
<br />
One of the folks over at <b><a href="https://www.canva.com/">Canva</a></b> asked that give them a shout out. They have a basic free photo editor at <a href="https://photo-editor.canva.com/">https://photo-editor.canva.com</a> and their full product is at <a href="https://www.canva.com/">https://www.canva.com</a>. Ken and I haven't used it yet in a real project yet, but it might be worth checking out. Leave some feedback and let us know if you tried it out and if you liked it or not.<br />
<br />
- Tod</div>
Kenhttp://www.blogger.com/profile/13873624059581511454noreply@blogger.com1tag:blogger.com,1999:blog-8061157626403355683.post-65681320873627696752011-11-07T04:00:00.000-08:002011-11-07T04:00:16.504-08:00Integrating Social Media - Epic FailI plan on returning to my multi-part series on creating a <a href="http://fivelakesstudio.blogspot.com/2011/10/star-rating-system-part-1-google-app.html">Star Rating System</a> in a future post. This week, I wanted to take a small side detour and talk about how Ken and I have tried to integrate social media into our games. Or perhaps I should say, how we have failed at it miserably. I'm hoping someone will share some words of wisdom as there must be something fundamentally wrong with our approach thus far.<br />
<br />
<br />
<b>iOS 5 Twitter</b><br />
<br />
With iOS5 Twitter integration, I thought it would be great to add twitter to <a href="http://bit.ly/ppdGMA">Kento</a>. I created a little twitter helper class based on the <a href="http://tonyngo.net/2011/10/twitter-integration-tutorial/?utm_source=rss&utm_medium=rss&utm_campaign=twitter-integration-tutorial">iDevBlogADay article by Tony Ngo</a>. The class source is just two files and is available for <a href="http://bit.ly/FLTwitter">download</a>. <br />
<br />
I added a twitter button to two places within Kento: on the main screen and when you solve a puzzle.<br />
<br />
On the main screen, there is a tweet button that pre-fills in the number of tokens the player has won and a link to Kento.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9jOZscklMNDhHthZ6eZUOWCmuQFIkbV9zK9LgzHO9KvDuoD_MJg-c7yU3pu1hxDj_LyzuIyOi8JVjykkemBrz0Q4k-8sYYQRY6jndgmAVhysRbUdg3dinIoD995dzfrocFk1cc7oeGuR-/s1600/2011-11-06_03-19-38.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9jOZscklMNDhHthZ6eZUOWCmuQFIkbV9zK9LgzHO9KvDuoD_MJg-c7yU3pu1hxDj_LyzuIyOi8JVjykkemBrz0Q4k-8sYYQRY6jndgmAVhysRbUdg3dinIoD995dzfrocFk1cc7oeGuR-/s400/2011-11-06_03-19-38.png" width="205" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpTasz3LIkQnz_ddkBNnGaQmhh30q8JmbF-I4ZdTU-4PC42i1ACgZ1A972Job6O1xsDNXJtWkJNutuhWcHxSb5E8P5YVGtB3WAQDABEkmLcAPvKwNSeNgZ0e96iLKKqfUV0yc8wPcfvHZI/s1600/2011-11-06_03-19-10.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpTasz3LIkQnz_ddkBNnGaQmhh30q8JmbF-I4ZdTU-4PC42i1ACgZ1A972Job6O1xsDNXJtWkJNutuhWcHxSb5E8P5YVGtB3WAQDABEkmLcAPvKwNSeNgZ0e96iLKKqfUV0yc8wPcfvHZI/s320/2011-11-06_03-19-10.png" width="320" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
When the player solves a puzzle, we place a tweet button in the upper left corner that pre-fills in some nice information about the puzzle along with a picture.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOYKw07kf0cxt1Qol5vm-HX0WIH_xJ6fg8rHBU6ai0oMOIrfTokwYQ2RiVC3dkPeHLa_UudmqOyRNU7MUpy0XNdaZCa6W8JeI_SWjz9hE8URQDT6tTJdxp5_2HhlfmpQR-oxVSrRB7Z0Vd/s1600/2011-11-06_03-23-32.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOYKw07kf0cxt1Qol5vm-HX0WIH_xJ6fg8rHBU6ai0oMOIrfTokwYQ2RiVC3dkPeHLa_UudmqOyRNU7MUpy0XNdaZCa6W8JeI_SWjz9hE8URQDT6tTJdxp5_2HhlfmpQR-oxVSrRB7Z0Vd/s320/2011-11-06_03-23-32.png" width="320" /></a></div>
<div style="margin-left: 1em; margin-right: 1em; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXNJkbawr6KfC8hH6WpVOw8LHQfyYkUosuHQjLocAtMc6CD45FeztMlQM-nzqAIgC0BrBXIirowPQf5jZAHfajQzwXx6ZykRg5y_TPMgzdfXWe2jKuJ80wqkKuFF9Tq0e9rUDB8F4iejTe/s1600/2011-11-06_03-23-06.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXNJkbawr6KfC8hH6WpVOw8LHQfyYkUosuHQjLocAtMc6CD45FeztMlQM-nzqAIgC0BrBXIirowPQf5jZAHfajQzwXx6ZykRg5y_TPMgzdfXWe2jKuJ80wqkKuFF9Tq0e9rUDB8F4iejTe/s400/2011-11-06_03-23-06.png" width="205" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The version with twitter was released about two weeks ago and we have over 17,000 updates/downloads. Can you guess how many times I have seen #KentoApp tweeted or received a tweet to @fivelakesstudio from Kento? The answer is .......... ZERO, if you don't count my test ones.<br />
<br />
<br />
<br />
<br />
<br />
<div style="text-align: left;">
<br /></div>
<b>A Previous Attempt</b><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAac40zv0-doQBoElsbVjodonkvFD_bFZ6Kq-OHh_mQzb6tioTku1F7lhNXikpef-F9DLNAtIXM7zMMwhjix5IFA3ZExqfuEkht3FiUnEDhr_DYGEMRjEdRfm5kLH_faR2Af8nDbjvO60T/s1600/2011-11-06_03-52-18.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAac40zv0-doQBoElsbVjodonkvFD_bFZ6Kq-OHh_mQzb6tioTku1F7lhNXikpef-F9DLNAtIXM7zMMwhjix5IFA3ZExqfuEkht3FiUnEDhr_DYGEMRjEdRfm5kLH_faR2Af8nDbjvO60T/s640/2011-11-06_03-52-18.png" width="368" /></a>We tried integrating facebook into <a href="http://bit.ly/fls_lost">#Lost in Space</a> with the same result: ZERO usage. People just don't click on the facebook icon.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
We show a little icon and some game text when the player tries to share their score through Facebook.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh5qPTct8oNRrsV-OPRjsHVNH3IaCDFYYk6aiviTZUjJsG4JCFd1uMFaaF_h3_BwXPaHuKvMdrHff7sI-zoUcxCCFgWppzsaOOTRwF0RP6kHd_YjS87VlfwvMkyPywwWxpj5n7-Arnnu-w/s1600/2011-11-06_03-51-12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh5qPTct8oNRrsV-OPRjsHVNH3IaCDFYYk6aiviTZUjJsG4JCFd1uMFaaF_h3_BwXPaHuKvMdrHff7sI-zoUcxCCFgWppzsaOOTRwF0RP6kHd_YjS87VlfwvMkyPywwWxpj5n7-Arnnu-w/s400/2011-11-06_03-51-12.png" width="400" /></a></div>
<br />
<br />
<br />
<b>Conclusion</b><br />
<br />
The puzzle star rating system we added continues to get great usage, but we have totally failed at engaging other types of social media such as Facebook or Twitter within our games. We have also tried things such as <a href="http://www.heyzap.com/">HeyZap</a> which has had better results then Facebook or Twitter, but it still doesn't have the level of engagement and usage we would like to see. Has anybody had better luck at integrating social platforms? I'm thinking that slapping a button in a UI just isn't the right way to do this type of social integration.<br />
<br />
Thanks,<br />
Tod<br />
<br />
<br />
<br />
<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com2tag:blogger.com,1999:blog-8061157626403355683.post-32275518306050498262011-11-06T05:05:00.000-08:002011-11-06T05:07:51.274-08:00UIAlert with BlocksI wish Apple would make a version of UIAlert with blocks. I have seen a fair number of simple examples on how to do this, but I have been unhappy with most of them. Most use Categories on UIAlert, and I would rather not do that especially when the alert handler is also involved. <br />
<br />
This very simple implementation uses a separate class to implement a UIAlert. Here is how you use it:
<pre class="brush:objc">
TCAlert *alert = [[TCAlert alloc] initWithTitle:@"Reset Puzzles"
message:@"Reset ALL puzzles in this puzzle pack?"
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Yes", nil];
[alert showAlertWithCompletionBlock:^(int buttonIndex)
{
NSLog( @"Hello I got it %d", buttonIndex );
[alert release];
}];
</pre>
It is important that the alert object stay retained through the life of the Alert, but that is easy to do by releasing it in the block. The block will retain the alert! If the system closes the alert the completion block will be called with a buttonIndex of -1 (kAlertViewCanceled).<br />
<br />
The code is just a small source and header file. Please feel free to <a href="http://bit.ly/TCAlert">download it</a> and let me know what you think. I haven't switched over to ARC yet, so I'm not sure what would need to be changed to support ARC. It would be great if someone would like to do that.<br />
<br />
Thanks,<br />
- Tod<br />
<br />
<br />
<br />
<br />
<br />Todhttp://www.blogger.com/profile/11196421011601992924noreply@blogger.com0