tag:blogger.com,1999:blog-49745258310381928742015-06-14T22:25:37.864-07:00BJ HomerI work on Day One, a great journaling app. I mostly write about code and about being a Mormon. I'm @bjhomer on Twitter.BJ Homernoreply@blogger.comBlogger26125tag:blogger.com,1999:blog-4974525831038192874.post-58147874019317986102015-06-14T22:22:00.000-07:002015-06-14T22:25:37.889-07:00Thoughts on WWDC 2015In my mind, these are biggest developer-facing announcements to come out of WWDC 2015:<br /><ul><li>iPad Multitasking</li><li>UI Testing and Code Coverage in Xcode 7</li><li>Swift 2</li><li>Swift as an Open-Source language</li><li>App Thinning</li><li>Watch OS 2.0 with on-device apps</li><li>CloudKit Web Services</li><li>Free iOS provisioning</li></ul><div>Note that <i>these aren't changes in the SDK itself</i>. Developers don't have to write a lot of code to get these benefits. iPad multitasking already works if you followed the adaptivity guidance for iOS 8 from last year; support is as simple as recompiling. UI Testing works on your existing apps. On-watch WatchKit extensions use the same SDK that on-phone extensions used (albeit with additional capabilities exposed). You don't need to make any changes to your CloudKit usage in order to enable web services. All these features come essentially free for the developer.</div><div><i><br /></i></div><div>There are, of course, some nice SDK changes as well. UIStackView and NSCollectionView are very welcome additions to their respective platforms, but even these aren't really new; they're just parity features between the platforms. The various new extension points are nice, and the new gaming frameworks are probably a big deal for game developers. But as I see it, WWDC doesn't fundamentally change the kinds of apps I can write.</div><div><br /></div><div>The focus this year isn't on enabling new kinds of apps, but rather on improving the experience of the apps we can already build. App testing, delivery, performance, and consumption are all improved <i>across the board</i>, with little effort needed from developers. iOS 9 and OS X El Capitan offer significant improvements to the user experience, and Xcode 7 improves the developer experience, but the improvements are largely outside the SDK. The big news from WWDC 2015 isn't about new frameworks, classes, and methods—it's about an improved experience for users and developers.<br /><br /><br /><br /><span style="font-size: x-small;">Caveat: If you're a game developer, GameplayKit, ReplayKit, and the expanded Metal announcements may have made this a big year for you. I'm not a game developer, so they don't really affect me from a development standpoint. But I acknowledge that they definitely look cool, and are definitely part of the SDK.</span></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-48108175201974297872015-05-02T23:22:00.002-07:002015-05-03T08:20:09.984-07:00Defining Modules for Static Libraries<b>Preview:</b><br /><br />I figured out how to define modules for static libraries, so you can import them into Swift or into other module-defining frameworks. This solves a common build error: "<code>include of non-modular header inside framework module</code>", as it allows you to turn that non-modular header into a modular one.<br /><br />You just have to define a custom <code>module.modulemap</code> file and copy it into the right place. Read more for details, or skip to the end if you just want to know what to do.<br /><br /><hr /><br /><br /><b>A brief and incomplete rationale for modules</b><br /><br />In 2013, Xcode 5 was released with support for modules, a new way of using libraries and frameworks. Xcode 5 only supported modules in system libraries, but Xcode 6 extended support to third-party libraries as well. Before the advent of modules, developers gained access to libraries via <code>#import</code> statements, which literally copy the requested header files into the importing file. This made the library APIs visible within that file, but required repeatedly parsing system headers again and again as multiple files imported the same headers. This is an unnecessary duplication of work.<br /><br />We could greatly improve build times if the compiler could parse all the headers of a library just once. However, this is difficult in a <code>#import</code>-based system, because the compiler does not know what files constitute the canonical headers for any given library. Some libraries provide an "umbrella" header that imports all of its API, but the compiler can't always know what header that would be, and even these aren't always complete. (Example: <code>UIKit.h</code> does not import <code>UIGestureRecognizerSubclass.h</code>.) We needed a better way of defining the canonical interface for a given library.<br /><br />Modules are that better way. A module is a binary representation of a library's interface—once built, the module can be reused throughout the entire compilation process. It can also be used to provide access to the library from other languages, such as Swift. In fact, Swift code can only make use of frameworks and libraries that have a module defined, so this becomes a critical piece of infrastructure going forward.<br /><br /><b>Module maps</b><br /><br />So how <i>do</i> we define a module from a bunch of headers? How do we define the canonical API for a library? Module maps. A module map is a simple file that defines the canonical headers for a library. They're easiest to understand by example, so let's jump right in.<br /><br />The following is a valid module map for an imaginary library. It is place in a file named <code>module.modulemap</code> in the same directory as the library headers.<br /><br /><pre>module AirplaneKit {<br /> header "Airplane.h"<br /> header "AirplaneView.h"<br /> header "Cockpit.h"<br /> header "Fuselage.h"<br /> header "Wheels.h"<br /> header "Wings.h"<br />}</pre><br />Simple enough; the module map is just a list of headers that define the representation of the library. It can get a bit tedious to write out every header, though, and it's easy to forget to update the modulemap when you add a new header, so module maps support a convenient syntax:<br /><br /><pre>module AirplaneKit {<br /> umbrella header "AirplaneKit.h"<br /> export *<br />}</pre><br />That <code>export *</code> line means "Also consider any file imported by one of the listed headers to be part of the module." This is generally what you'll want to do. (The <code>umbrella</code> part is not strictly necessary, but indicates that the header is expected to import every header file in its directory.)<br /><br />In general, Xcode has fairly good support for defining modules based on your own frameworks: just set the <i>Defines Module </i>build setting to YES and maintain your framework's umbrella header. Xcode will build the appropriate module map file and embed it within your framework. Support for static libraries, though, is somewhat lacking.<br /><br />Before we move on, <b>one important note</b>: <i>In Xcode 6.3.1, you must clean your project after any change to a module.modulemap file.</i> In my experience, the compiled version of the module is not rebuilt when the module map file changes. Also, when tweaking the module map file, make sure you're editing your original file, not the one in the build folder. Xcode sometimes likes to jump to that one instead.<br /><br /><b>Defining modules for static libraries</b><br /><b><br /></b>If you're using a static library and you want to make it available to Swift or to another module, there are 2 things you need to do to "modularize" it.<br /><br /><div class="separator" style="clear: both; text-align: center;"></div><b>1. </b>Add a file named exactly <code>module.modulemap</code> as described above.<br /><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-9wmIhjnKDk8/VUW5OFI5WcI/AAAAAAAAAzI/ykHO5kBl_6s/s1600/Screen%2BShot%2B2015-05-02%2Bat%2B11.59.03%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="77" src="http://2.bp.blogspot.com/-9wmIhjnKDk8/VUW5OFI5WcI/AAAAAAAAAzI/ykHO5kBl_6s/s320/Screen%2BShot%2B2015-05-02%2Bat%2B11.59.03%2BPM.png" width="320" /></a></div><div><b>2a.&nbsp;</b>If you're using someone else's library you didn't write, you probably already put the headers somewhere. Just write a module map file for the library and put it with the headers.<br /><br /><b>2b. </b>If you're building your own static library, make sure your library's headers <i>and the module map</i> are being copied to <code>[build directory]/include/[LibraryName]/</code>. If your static library target is using a Copy Headers build step (as is the default in Xcode 6.3.1), <a href="https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Articles/creating.html#//apple_ref/doc/uid/TP40012554-CH2-SW4" target="_blank">remove it</a>. Instead add a Copy Files build phase, configured as follows:</div><div><div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/--5xFzrs99zs/VUY72-avY6I/AAAAAAAAAz0/eCSAF9H7dhg/s1600/Screen%2BShot%2B2015-05-03%2Bat%2B9.14.41%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="151" src="http://3.bp.blogspot.com/--5xFzrs99zs/VUY72-avY6I/AAAAAAAAAz0/eCSAF9H7dhg/s320/Screen%2BShot%2B2015-05-03%2Bat%2B9.14.41%2BAM.png" width="320" /></a></div></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><hr /><br /></div><div>That's it. Really. After doing the above, you can now use your library from Swift. You can read more about modules and the modulemap format in the <a href="http://clang.llvm.org/docs/Modules.html" target="_blank">Clang Documentation</a>.<br /><br />If you have any problems, please let me know on Twitter (<a href="https://twitter.com/bjhomer" target="_blank">@bjhomer</a>). I'd like to make sure these steps work for everyone.</div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-44060793078808912642014-10-18T19:36:00.005-07:002014-10-18T23:23:03.804-07:00Mutable collections in SwiftI recently came across this question on Twitter:<br /><br /><blockquote class="twitter-tweet" lang="en">Hey <a href="https://twitter.com/hashtag/swiftlang?src=hash">#swiftlang</a> peeps: How do you create an var that holds an immutable Array? As in a var that you can assign different immutable Arrays to?<br />— Mike R. Manzano (@bffmike) <a href="https://twitter.com/bffmike/status/523244788691107841">October 17, 2014</a></blockquote><script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script><br />This is an interesting question. As a developer coming from Objective-C and the Cocoa frameworks, we're used to distinguishing between <code>NSArray</code> and <code>NSMutableArray</code>. It's generally bad practice to expose an <code>NSMutableArray</code> as a public property on an object.<br /><br /><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=1-public-nsmutablearray.m"></script><br />The problem is that another part of the app could modify the contents of the <code>pizzaMenu</code> array without the knowledge of the <code>Pizzeria</code> object. The <code>Pizzeria</code> still points to the same object it always has; from its perspective, nothing has changed. This is bad.<br /><br /><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=2-modifying-pizza-menu.m"></script><br />Instead, a better practice is to only expose an immutable <code>NSArray</code>. This way, whenever any change happens, the setter method will be called. The <code>Pizzeria</code> is always aware of what's happening.<br /><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=3-public-nsarray.m"></script><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=4-modifying-public-nsarray.m"></script></div><div>In Swift, the <code>Array</code> type is built into the language. Though you can still use <code>NSArray</code> and <code>NSMutableArray</code>, it's often not necessary; the native Array type is plenty capable.</div><div><br /></div><div>There are two types of objects in Swift: value types and reference types. Reference types are like traditional Objective-C objects—multiple variables can <i>reference</i> the same object. This was the problem in the examples above above: both the <code>Pizzeria</code> object and external code referenced the same object, so we had to expose an <code>NSArray</code> that does not have APIs for changing its contents.</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=5-reference-types.m"></script></div><div>Value types are identified by their value. They also exist in Objective-C, but only for C types (structs and primitives). If two <code>CGRect</code> variables have the same value, it simply means that the two rects contain the same data. A change to one rect will never change the value of another rect stored in a separate variable.</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=6-value-types.m"></script></div><div>While Objective-C requires that all objects be reference types, Swift objects can be reference or value types. This means that Swift <code>struct</code>s can have methods just like <code>class</code>es can. Swift's built-in collections (<code>Array</code> and <code>Dictionary</code>) are <i>value</i> types.</div><div><br /></div><div>Because they are value types, two variables can never reference the "same" array. Every time an array is assigned to a variable, it gets a new, separate copy<sup><a href="#footnote1" name="ref1">1</a></sup> which cannot be affected by any other part of the code.</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=7-separate-arrays.swift"></script></div><div>This means <b>there is no need for a separate mutable collection type</b> in Swift. Mutating a value type is always safe because changing a struct only affects the values of that specific variable. That what it means to be a value type. Modifying a Swift <code>Array</code> never affects any other variable, anywhere.</div><div><br /></div><div>Let's see how this affects our pizzeria example.</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=8-swift-pizzeria.swift"></script></div><div>Note that even though <code>pizzeria.pizzaMenu</code> is a mutable <code>var</code> property, modifying the array we get back from the pizzeria has no effect on the pizzeria's copy of the data. They are separate arrays, separate values, and we can't change their copy unless we go through the setter.</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=9-using-swift-pizzeria.swift"></div><div></script></div><div>In fact, this holds true even if we avoid assigning the array to an intermediate variable! In Objective-C, you simply cannot modify a value type held by another object. Many iOS developers have discovered this, to their frustration:</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=_10-direct-modification.m"></script></div><div>But in Swift, not only does this work, but it guarantees that the setter will be called! Whenever you call a mutating<sup><a href="#footnote2" name="ref2">2</a></sup> method on a value type, the end result is assigned back into the receiving variable (or expression). So calling <code>obj.someInts.append(1)</code> causes a new value to be constructed, which is then assigned back into the <code>someInts</code> property!</div><div><br /></div><div><script src="https://gist.github.com/bjhomer/57475e5419a2fa736c03.js?file=_11-direct-modification.swift"></script></div><div><br /></div><div>Because Swift arrays and dictionaries can never be shared, there is no distinction between mutating an existing collection and re-assigning a new collection. The behavior of the code is exactly the same. In either case, the owner's setter method is called whenever the array is modified.</div><div><br /></div><div>So to answer the original question, there is no syntax to specify a variable that holds an immutable array because there is nothing that such syntax would add. Swift addresses the issues that made <code>NSArray</code> and <code>NSMutableArray</code> necessary in the first place. If you need a shared array, you can still use the Cocoa types. In every other case, Swift's solution is safer, simpler, and more concise.</div><div><br /><hr /></div><div><br /></div><div><span style="font-size: small;"><span id="footnote1">1</span>: Note that the implementation is lazy, only performing an <i>actual</i> copy when really necessary. <a href="#ref1">↩</a></span></div><div><span style="font-size: small;"><span id="footnote2">2</span>: Methods on structs and enums in Swift must be labeled <code>mutating</code> if they're going to modify any data. Otherwise, they cannot be called on a value stored in a <code>let</code> variable. <a href="#ref2">↩</a></span></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-38167410130724512372014-08-08T08:59:00.001-07:002014-08-08T09:05:04.247-07:00NSScrollView and AutolayoutSo, you've got an NSScrollView, and you want to add some content that is sized via auto layout constraints. Perhaps you found the "<a href="https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html#//apple_ref/doc/uid/TP40010853-CH5-SW2">Auto Layout by Example</a>" documentation in the Mac developer library, and discovered that though it contains a section titled <i>Using Scroll Views with Auto Layout,</i>&nbsp;the example is actually for UIScrollView, not NSScrollView. Given the significant differences between the two, that simply won't work.<br /><br />Here's what you need to do. I'll demonstrate doing this in code, but the same principles apply in Interface Builder as well.<br /><br /><br /><br />1. Create an NSScrollView. Position it however you like.<br /><br /><div style="color: #3d1d81; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;&nbsp;</span><span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> = [[</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">NSScrollView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> </span>alloc<span style="color: black; font-variant-ligatures: no-common-ligatures;">] </span>initWithFrame<span style="color: black; font-variant-ligatures: no-common-ligatures;">:</span><span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">self</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">bounds</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">];</span></div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span><span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span>translatesAutoresizingMaskIntoConstraints<span style="color: black; font-variant-ligatures: no-common-ligatures;"> = </span><span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">YES</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">;</span></div><div style="color: #3d1d81; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span><span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">autoresizingMask</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> = </span>NSViewHeightSizable<span style="color: black; font-variant-ligatures: no-common-ligatures;"> | </span>NSViewWidthSizable<span style="color: black; font-variant-ligatures: no-common-ligatures;">;</span></div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span><span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span>hasVerticalScroller<span style="color: black; font-variant-ligatures: no-common-ligatures;"> = </span><span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">YES</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">;</span></div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: #4f8187;">&nbsp; &nbsp; _scrollView</span><span style="color: black;">.</span>identifier<span style="color: black;">&nbsp;=&nbsp;</span><span style="color: #d12f1b;">@"ScrollView"</span><span style="color: black;">;</span></div><br /><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; [</span><span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">self</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">addSubview</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:</span>_scrollView<span style="color: black; font-variant-ligatures: no-common-ligatures;">];</span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;"><br /></span></div><br />2. Create an NSView subclass with isFlipped == YES that will contain all your scrolling content. &nbsp;(If it's not flipped, then the content will prefer to pin to the <i>bottom</i>&nbsp;of the scroll view if not tall enough to require scrolling. That's not what you want.)<br /><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-family: Times; font-size: small;"><br /></span></div><div style="font-family: Menlo; font-size: 11px;"><span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; @interface</span> FlippedView : NSView</div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; <span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">@end</span></div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;"><br /></div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; <span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">@implementation</span> FlippedView</div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;"><br /></div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; - (<span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">BOOL</span>)isFlipped {</div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">return</span> <span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">YES</span>;</div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; }</div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;"><br /></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"></div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; <span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">@end</span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-family: Times; font-size: small;"><br /></span></div>3. Create the scrolling container view. Do <i style="color: black; font-family: Times; font-size: medium;">not</i> use autoresizing masks. Its size doesn't matter too much, but its superview will be the&nbsp;scroll view's contentView, so that makes a convenient default size.<br /><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-family: Times; font-size: small;"><br /></span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;&nbsp;</span>_scrollContentContainer<span style="color: black; font-variant-ligatures: no-common-ligatures;"> = [[</span>FlippedView<span style="color: black; font-variant-ligatures: no-common-ligatures;"> </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">alloc</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">]</span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;"></span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; initWithFrame</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:</span>_scrollView<span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">contentView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">bounds</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">];</span></div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span><span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollContentContainer</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span>translatesAutoresizingMaskIntoConstraints<span style="color: black; font-variant-ligatures: no-common-ligatures;"> = </span><span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">NO</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">;</span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span>_scrollContentContainer<span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">identifier</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> = </span><span style="color: #d12f1b; font-variant-ligatures: no-common-ligatures;">@"Content container"</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">;</span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;"><br /></span></div>4. Set the content container to be the scroll view's document view.<br /><br /><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span>_scrollView<span style="color: black; font-variant-ligatures: no-common-ligatures;">.</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">documentView</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> = </span>_scrollContentContainer<span style="color: black; font-variant-ligatures: no-common-ligatures;">;</span></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><br /></div>5. Constrain the top, left, and right edges of the container view to its superview (the contentView). Use&nbsp;Auto Layout constraints to do this, not autoresizing masks.<br /><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-family: Times; font-size: small;"><br /></span></div><div style="color: #78492a; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;&nbsp;</span><span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">NSDictionary</span><span style="color: black; font-variant-ligatures: no-common-ligatures;"> *views = </span>NSDictionaryOfVariableBindings<span style="color: black; font-variant-ligatures: no-common-ligatures;">(</span><span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollContentContainer</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">);</span></div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;&nbsp;</span>NSArray<span style="color: black; font-variant-ligatures: no-common-ligatures;"> *hConstraints = [</span>NSLayoutConstraint</div><div style="color: #d12f1b; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">constraintsWithVisualFormat</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:</span>@"H:|[_scrollContentContainer]|"</div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">options</span>:<span style="color: #272ad8; font-variant-ligatures: no-common-ligatures;">0</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">metrics</span>:<span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">nil</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">views</span>:views];</div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;">&nbsp;&nbsp; &nbsp;</div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span>NSArray<span style="color: black; font-variant-ligatures: no-common-ligatures;"> *vConstraints = [</span>NSLayoutConstraint</div><div style="color: #d12f1b; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">constraintsWithVisualFormat</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:</span>@"V:|[_scrollContentContainer]"</div><div style="color: #d12f1b; font-family: Menlo; font-size: 11px;"></div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">options</span>:<span style="color: #272ad8; font-variant-ligatures: no-common-ligatures;">0</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">metrics</span>:<span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">nil</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">views</span>:views];</div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp;&nbsp;[<span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollView</span>.<span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">contentView</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">addConstraints</span>:hConstraints];</div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; [<span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollView</span>.<span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">contentView</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">addConstraints</span>:vConstraints];</div><div style="font-family: Menlo; font-size: 11px;"></div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;">&nbsp; &nbsp;&nbsp;</div>6. Add your subviews to the content container however you like. Make sure that the constraints from these subviews will create a natural content size in at least the vertical dimension.<br /><br /><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp;&nbsp;<span style="color: #703daa; font-variant-ligatures: no-common-ligatures;">NSDictionary</span> *buttons = <span style="color: #78492a; font-variant-ligatures: no-common-ligatures;">NSDictionaryOfVariableBindings</span>(button, button2);</div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span>NSArray<span style="color: black; font-variant-ligatures: no-common-ligatures;"> *hConstraints2 = [</span>NSLayoutConstraint</div><div style="color: #d12f1b; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">constraintsWithVisualFormat</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:</span>@"V:|-[button]-(1300)-[button2]-|"</div><div style="color: #3d1d81; font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;options: (NSLayoutFormatAlignAllLeft |<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NSLayoutFormatAlignAllRight)</div><div style="font-family: Menlo; font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">metrics</span>:<span style="color: #bb2ca2; font-variant-ligatures: no-common-ligatures;">nil</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">views</span>:buttons];</div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;">&nbsp;&nbsp; &nbsp;</div><div style="color: #703daa; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; </span>NSLayoutConstraint<span style="color: black; font-variant-ligatures: no-common-ligatures;"> *centerX = [</span>NSLayoutConstraint</div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">constraintWithItem</span>: button</div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">attribute</span>: <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">NSLayoutAttributeCenterX</span></div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">relatedBy</span>: <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">NSLayoutRelationEqual</span></div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">toItem</span>:&nbsp; &nbsp; <span style="color: #4f8187; font-variant-ligatures: no-common-ligatures;">_scrollContentContainer</span></div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">attribute</span>: <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">NSLayoutAttributeCenterX</span></div><div style="font-family: Menlo; font-size: 11px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">multiplier</span>:<span style="color: #272ad8; font-variant-ligatures: no-common-ligatures;">1</span> <span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">constant</span>:<span style="color: #272ad8; font-variant-ligatures: no-common-ligatures;">0</span>];</div><div style="font-family: Menlo; font-size: 11px; min-height: 13px;">&nbsp;&nbsp; &nbsp;</div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; [</span>_scrollContentContainer<span style="color: black; font-variant-ligatures: no-common-ligatures;"> </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">addConstraints</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:hConstraints2];</span></div><div style="font-family: Menlo; font-size: 11px;"></div><div style="color: #4f8187; font-family: Menlo; font-size: 11px;"><span style="color: black; font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; [</span>_scrollContentContainer<span style="color: black; font-variant-ligatures: no-common-ligatures;"> </span><span style="color: #3d1d81; font-variant-ligatures: no-common-ligatures;">addConstraint</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">:centerX];</span></div><div><br /><br />Of course, you can do this all in Interface Builder as well, and that's usually what I'd do. It's nice to know how to do it both ways, though. The same principles apply in either case:<br /><br /><ol><li>Position the NSScrollView externally however you like.</li><li>Flipped container view as the scroll view's document view.</li><li>Constraints from top, right, and left of container view to its superview.</li><li>Constraints from the scrollable content to the container view.</li></ol><br />And that's it!</div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-80981461359546087962014-08-05T22:39:00.002-07:002014-08-05T22:39:47.475-07:00Mormon Questions: TemplesA couple weeks ago, my brother was married in the temple in Bountiful, Utah. Temples are an important part of my beliefs as a member of the Church of Jesus Christ of Latter-Day Saints, so I thought I'd take some time to explain what they're about and answer some common questions.<br /><br />First, though, a brief note. To understand our temples, you must understand that our religion is not just a codified series of moral guidelines. We believe that God is a real, physical being who communicates with us and blesses us as we follow his teachings. We also believe that each of us has a spirit which continues to live on after our death. The temple binds us to God eternally, far beyond our brief time here on Earth. If you try to understand the temple while ignoring these things, the things we do in the temple will make very little sense.<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://www.lds.org/media-library/images/temples/bountiful-utah?lang=eng" imageanchor="1" style="margin-left: auto; margin-right: auto;" target="_blank"><img border="0" src="http://4.bp.blogspot.com/-9-MR6NgL05Q/U9ZFqyBbFNI/AAAAAAAAAuY/JAN-KFRfO3E/s1600/bountiful-temple-766347-tablet.jpg" height="424" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Bountiful, Utah temple. Click to see more photos.</td></tr></tbody></table><h4>Outside the temple</h4><div class="separator" style="clear: both; text-align: left;">If you know anything about Mormon temples, you probably know that they've got beautiful architecture. Temples usually have stained glass windows, intricate stonework, and a design that draws the eye heavenward. Each temple is built to be a house of the Lord, a place where God is welcome. Quite literally, the phrase "The House of the Lord" is inscribed on the exterior of every temple. We make every effort to make each temple a beautiful place, representative of the respect and love we have for God.</div><div class="separator" style="clear: both; text-align: left;"><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://www.lds.org/media-library/images/temples/madrid-spain?lang=eng" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="" border="0" src="http://1.bp.blogspot.com/-LAgwrc5XlRA/U9nkN1_Aj5I/AAAAAAAAAuo/luvauPjR8ms/s1600/house-of-the-lord.jpg" height="265" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">"Holiness to the Lord. The House of the Lord."<br />Temple in Madrid, Spain</td></tr></tbody></table><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The grounds of each temple are generally open to the public and show the same dedication to serenity and peacefulness. They usually feature gardens and fountains, shade trees and benches, and it's common to see people taking pictures on the grounds or sitting on a bench study scriptures. Many temples also have visitor's centers, where guests can get more information and ask questions.</div><div class="separator" style="clear: both; text-align: left;"><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="http://2.bp.blogspot.com/-KlqUgu2rJOk/U9nquCQQYkI/AAAAAAAAAu4/jPyEZnMtuM8/s1600/temple-fountain.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-KlqUgu2rJOk/U9nquCQQYkI/AAAAAAAAAu4/jPyEZnMtuM8/s1600/temple-fountain.jpg" height="266" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Fountain at the Oakland, California temple</td></tr></tbody></table><h4>Inside the temple</h4><div class="separator" style="clear: both; text-align: left;">Temples are sacred buildings where we participate in ordinances (religious rituals or ceremonies) and make covenants with God. They are set apart from the outside world, dedicated to a specific purpose and free from external distractions. Upon entering, attendees change into white clothing and leave behind cell phones and other distractions. The temple is a quiet, peaceful, and reverent place. We are asked to speak in a whisper if we speak at all. Some rooms are set aside simply for contemplation and prayer, while others are meant to accommodate a specific ordinance.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">If you've visited the churches or cathedrals of other religions, you might expect the interior of the temple to be a vast open space. In fact, the interior of each temple is simply a series of rooms, each with its own purpose. There are ceremonial rooms, administrative offices, hallways, chapels, and small meeting rooms, but no massive space for congregating. The same care that goes into the exterior of the temple goes into the interior as well; there are crystal chandeliers, intricate carvings and designs, beautiful stairways, etc. You can find some pictures of the <a href="https://www.lds.org/church/temples/why-we-build-temples/inside-the-temple?lang=eng" target="_blank">interior of the temple on lds.org</a>. (I was unable to find good photos of the temple interior that were licensed for use on other websites, so I'm afraid you'll just have to&nbsp;follow the link&nbsp;on this one.)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Temples are distinct from our meetinghouses, where regular Sunday worship takes place. In meetinghouses, we gather each week to learn about Christ through scripture study, talks, hymns, etc. We also take the sacrament (often known as "communion" in other Christian religions.) None of this happens in temples; in fact, our temples are not even open on Sundays. Temples are specifically focused on sacred ceremonies, not worship services. (If you're interested in attending one of our Sunday meetings, you can find a nearby meetinghouse <a href="http://www.mormon.org/meetinghouse" target="_blank">on mormon.org</a>.)</div><div class="" style="clear: both; text-align: left;"><h4>Temple ordinances (ceremonies)</h4><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="http://3.bp.blogspot.com/-Jisy3YwB9uY/U95Eq55duoI/AAAAAAAAAvI/AhxoioEWIIM/s1600/IMG_2323.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-Jisy3YwB9uY/U95Eq55duoI/AAAAAAAAAvI/AhxoioEWIIM/s1600/IMG_2323.jpg" height="300" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">That's my brother and sister-in-law. They're awesome.</td></tr></tbody></table>The most celebrated ordinance held in the temple is <i>eternal&nbsp;marriage</i>. Mormons believe that a marriage under proper authority in the temple is effective not only "until death do you part," but throughout eternity. Mormons are known for a strong emphasis on the family, and this is part of the reason why—we believe that family life is not just a transient phase while we're here on earth, but rather an essential part of our eternal future. In the temple, couples are "sealed&nbsp;together" for time and all eternity, creating a new family unit that will last forever.<br /><br />Another ceremony held in the temple is known as the <i>endowment</i>. It includes instruction about the pre-mortal existence of man, the creation of the world, the story of Adam and Eve in the Garden of Eden, and their path back to God's presence. As with many scriptural accounts, the lessons to be learned from the endowment are not necessarily the literal ones in the text. Just as Christ wasn't teaching us that we should all literally build our houses upon rocks, the endowment isn't really instruction about how to live in the Garden of Eden. It's symbolic, a metaphor for our own lives. During the endowment, we make covenants (promises) to follow the teachings of Jesus Christ and to participate in his Church.<br /><br />After we have received ordinances for ourselves, we can also go to the temple to receive <i>ordinances for the dead.</i>&nbsp;This may seem unfamiliar, but it's a beautiful concept.&nbsp;Religious ordinances (baptism, endowment, marriage, etc.) enable us to live with God again and to receive tremendous opportunities and blessings. Without these ordinances, we cannot ever receive all that God wants to give us. However, there are many, many people who have died without ever having the opportunity to participate in these ordinances. It might seem that millions upon millions of God's children are condemned by no fault of their own.<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://www.lds.org/media-library/images/salt-lake-temple-lds-593672?lang=eng&amp;category=" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="" border="0" src="http://4.bp.blogspot.com/-eYGcs_xW-a0/U-GsaDmZqNI/AAAAAAAAAvg/l0Xc8tdHJM4/s1600/salt-lake-temple-lds-593672-tablet.jpg" height="287" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Baptistry in the Salt Lake City temple</td></tr></tbody></table><br />But God cares about <i>all</i>&nbsp;of his children.&nbsp;We believe that those who never had an adequate chance to learn about Jesus Christ and his teachings in this life will have that opportunity in the next life, being taught by those who have previously learned it. But learning is not enough; ordinances such as baptism are required for our eternal progression, and it's rather difficult to baptize a spirit. So, after we (the living) have received these ordinances for ourselves, we can go to temples as a proxy for those who have died, and participate in various ordinances on their behalf. We are especially urged to do this work for our own ancestors, offering them the same opportunities that we have received. Baptisms for the dead, endowments for the dead, and even marriages for the dead are all performed in the temple in order to extend the blessings of each ordinance to those who have gone before.<br /><br />It would be incorrect, though, to say <i>"Well, we've done a baptism for Gertrude Hazelswatch (born in 1628), so now she's a Mormon too."</i>&nbsp;When we participate in temple ceremonies on behalf of the dead, we are only offering up the physical part of the ordinance. Each deceased person continues to live on as a spirit, and the baptism we perform on their behalf means nothing unless that person accepts the associated commitments. If they do not accept the commitments associated with baptism, they are not bound by them and the baptism means nothing. However, we cannot know who will accept or reject these commitments, so we offer them to as many as we can and hope that they will accept it.<br /><h4>Visiting the temple</h4></div><div class="" style="clear: both; text-align: left;">In order to preserve the reverent atmosphere that exists in temples, dedicated temples are only open to church members in good standing. However, after construction on a temple is completed, a temple "open house" event is held over several weeks. During this time, the public is invited to tour the temple. These open houses are usually very well attended, as it is the only chance for the general public to enter the temple. There are only a few temples built each year worldwide, so these open houses are fairly rare. If you happen to be in Utah this month, it might be worth your time to visit the Ogden, Utah temple open house, roughly 45 minutes north of Salt Lake City. The temple has been undergoing major renovations, and will be dedicated in September 2014. Reservations to attend are <a href="https://templeopenhouse.lds.org/tickets" target="_blank">available free online</a>.<br /><br />There's also a temple nearing dedication in Phoenix, Arizona. Open House dates have not yet been announced, but it will probably be late 2014.<br /><br />If you're not going to be able to catch an open house, you might be interested in stopping by a visitor's center. There are 143 temples in operation around the world, including many throughout North America, and most temples have visitor's centers that are open 7 days a week. You can find a <a href="https://www.lds.org/church/temples/find-a-temple?lang=eng" target="_blank">list of temples here</a>.<br /><br />And that's it! If you've got a question I didn't answer or if you just want to tell me what you think, feel free to ask me on Twitter (<a href="http://twitter.com/bjhomer">@bjhomer</a>) or send me an email (<a href="mailto:bjhomer@gmail.com">bjhomer@gmail.com</a>).</div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-54220294330585210002014-05-26T16:03:00.001-07:002014-10-18T23:29:46.512-07:00WWDC 2014 WishlistWWDC 2014 starts one week from today, so I guess that means it's time for some predictions. It's almost certain Apple will be introducing OS X 10.10 and iOS 8, which means new features, new APIs, and lots and lots of "To Be Announced" sessions. Last year, 64 of 97 sessions (65%) were marked "To Be Announced" prior to the keynote. This year, 80 of 108 sessions (74%) are still undisclosed<sup><a id="ref1" href="#footnote1">1</a></sup>. There's a lot of new stuff coming. <a href="http://bjhomer.blogspot.com/2013/06/anticipating-wwdc-2013.html">Last year</a> I was pretty conservative, only predicting things I was pretty sure of. This year, I don't know enough to do that, so I'm going to be a bit more speculative. Here's what I'm hoping for:<br /><h3>OS X 10.10</h3><h4><span style="font-weight: normal;">Rumors are strong that we'll see a visual overhaul of OS X, similar in scope to what iOS 7 brought last year. I really have no&nbsp;clue what to expect in&nbsp;general, but a few things seem more likely to change than others:</span></h4><div><ul><li><span style="font-weight: normal;"><b>No more gradient toolbar buttons (as found in Finder, Safari, etc.)</b><br />I would be very surprised if we don't see these transition to a more flat style. &nbsp;We saw the same sort of transition from Xcode 4.6 to Xcode 5. Expect that gradient buttons will be rare, especially in toolbars. I don't think the new style will look just like Xcode 5—I expect we're in for more of a change than that—but I'd be surprised if this isn't part of it.</span></li><span style="font-weight: normal;"> </span></ul></div><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="http://4.bp.blogspot.com/-kUZRLf_XpO8/U4Nt0SXIF0I/AAAAAAAAAtQ/skQCr5dqhXU/s1600/Screen+Shot+2014-05-26+at+7.59.05+AM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-kUZRLf_XpO8/U4Nt0SXIF0I/AAAAAAAAAtQ/skQCr5dqhXU/s1600/Screen+Shot+2014-05-26+at+7.59.05+AM.png" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Finder in OS X 10.9</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;"><a href="http://2.bp.blogspot.com/-kuKMfRyukrQ/U4NpCfAXtXI/AAAAAAAAAs4/Ja3M7Etjez0/s1600/Screen+Shot+2014-05-26+at+10.16.33+AM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-kuKMfRyukrQ/U4NpCfAXtXI/AAAAAAAAAs4/Ja3M7Etjez0/s1600/Screen+Shot+2014-05-26+at+10.16.33+AM.png" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Xcode 4.6</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;"><a href="http://3.bp.blogspot.com/-QC8SWi4Ve8E/U4NpJmkdiXI/AAAAAAAAAtE/qSopr_PsRSc/s1600/Screen+Shot+2014-05-26+at+10.16.43+AM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-QC8SWi4Ve8E/U4NpJmkdiXI/AAAAAAAAAtE/qSopr_PsRSc/s1600/Screen+Shot+2014-05-26+at+10.16.43+AM.png" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Xcode 5</td></tr></tbody></table></div><div><ul><li><b>Dock changes</b><br />The Dock seems like an obvious target for changes. Currently, the dock serves as a quick launcher, an app switcher, a container for minimized windows, a home for "Stacks," and the only visible location of the Trash icon. It's an unfocused mess.<br /><br />"Multiple, more-focused docks" is obviously not the right answer. They might remove running apps and just expect users to switch between them using Mission Control or by clicking on the window, but that just seems like it's removing functionality without any user benefit. Maybe they make it only show apps that currently have windows open? But then the quick-launch functionality is gone.<br /><br />So what does this all mean for the Dock? I'm not sure, really. But I think it's ripe for change; I'll be really surprised if the Dock stays exactly how it is right now.<br />&nbsp; </li><li><b>Open/Closed apps</b><br />I expect Apple to continue reducing the distinction between "running" and "non-running" apps. Recent features like Mission Control suggest that Apple feels managing visible windows is more important than managing apps. (See also the trend toward integrating "Inspector" panels into the main window.)&nbsp;There's already an option to remove the indicator lights for open applications in the Dock, and in past years, Apple has indicated that the Automatic Termination feature will become more and more prominent.<br /><br />The iOS app management model is an inspiration for Apple, I believe. iOS users generally don't worry about whether an app is "running" or not; they just know that if they can see it, they can use it. Obviously, on a desktop system with multiple windows visible at the same time, things are more complex. But if things are already getting reshuffled visually, expect more movement in this direction.<br />&nbsp; </li><li><b>Menu Bar</b><br />The global menu bar is one of the hallmarks of OS X. Windows migrants protest its disconnection from the window content. Mac veterans point out its consistent location and reliability.<br /><br />More and more, I feel that most users will never find features available only through the menu bar. Right-click contextual menus are far more accessible to users than the global menu bar. Increasingly, the standard&nbsp;<i>File</i>&nbsp;menu is more about managing windows and tabs than about files. The <i>View</i>&nbsp;menu usually manages the state of the window, and the <i>Window</i>&nbsp;menu is just a list of app windows that most people never use.<br /><br />Honestly, I don't really think we'll see significant changes to the menu bar itself. Changing it would break too many assumptions from existing apps. But I wouldn't be surprised if the built-in apps start abandoning the traditional <i>File, Edit, View, Window, Help</i>&nbsp;setup for a more user-friendly structure.<br />&nbsp;&nbsp; </li><li><b>Better access to iCloud documents</b><br />Currently, if an app saves a file in iCloud, that file is really only available from within that app. It shows up in Finder's <i>All My Files</i>&nbsp;view, but that list is so huge that it's mostly unmanageable. I'd love for Finder to have a view of files organized by app. Essentially, each app would be a "folder" for its documents.<br />&nbsp;</li><li><b>Siri</b><br />We'll probably see Siri show up on OS X at some point. Maybe it will be this year? It's possible, but I'm not counting on it. If it shows up, I'll consider it a nice surprise.<br />&nbsp; </li><li><b>Clock app</b><br />I said it <a href="https://twitter.com/bjhomer/statuses/463771972967464961" target="_blank">jokingly on Twitter</a>, but it actually wouldn't surprise me if OS X included an iPad-like Clock app. Stopwatch included.</li></ul><div>I suspect there will be lots of other exciting changes on OS X; I just don't know what they are. I'll look forward to this.</div></div><h3>iOS 8</h3><div>OS X is <a href="http://9to5mac.com/2014/05/01/os-x-10-10-focus-planned-for-wwdc-ios-8-features-pushed-to-ios-8-1-new-apple-tv-os-in-the-works/" target="_blank">rumored</a> to be the star of WWDC this year, but iOS will certainly have some new features too. The WWDC app lists 99 sessions with content relevant to iOS, and only 78 relevant to OS X. Some of this is surely just a reflection of the prominence of iOS in Apple's developer base, but it would be foolish to assume that iOS won't be getting anything interesting this year.&nbsp;</div><div><ul><li><b>App Services via Remote View Controllers&nbsp;</b><br />Back in October 2012, Ole Beggeman did some <a href="http://oleb.net/blog/2012/10/remote-view-controllers-in-ios-6/" target="_blank">great investigative work</a>&nbsp;on remote view controllers, used internally since iOS 6. The basic idea is that some portion of your app's interface is actually provided by a separate process. This is currently used for the Mail composition controller, for example; the pixels you see are actually generated in a separate app and then drawn into your app. Touches in that region are forwarded on to that helper app, such that everything appears to the user as if it all originated in the same app.<br /><br />Remote view controllers could resolve one of the longest-standing complaints about iOS—that apps are too "silo-ed off" from each other. Apps could instead provide interfaces to each other as "Services". Imagine if the Dropbox app could an interface for other apps to upload or download documents&nbsp;<i>from within their app</i>, without embedding a Dropbox SDK. Imagine if your university's LMS app could present a file-picking interface from Pages, and submit it as a homework submission for you. Or imagine if you could turn your Pages document as a homework submission <i>from within the Pages app</i>.<br /><br />This is the kind of thing that app services would allow. Of course, you'd have to have some programmatic way to discover available services and their purpose. Pages certainly isn't going to build in custom support for your university's LMS app. One approach might be for each app to declare the view controllers it can present in other apps via a plist. Each service might be labeled with its role, like these:<br /><br />&nbsp; <i>-</i>&nbsp;Document picker<br /><i>&nbsp; - </i>Sharing service<br />&nbsp; - Upload service<br /><br />The specific set of roles might expand over time, but the fundamental advantage is the ability for an app share its functionality with other apps on the system.<br />&nbsp;</li><li> <b>XPC and Sandboxing</b><br />XPC is a framework for creating and managing helper processes, introduced in OS X 10.7. It and allows the developer to segment their app into multiple processes. There are two main advantages to this structure: stability and privilege separation.<br /><br /><i>Stability</i> is a simple one to understand: If one of the helper processes crashes, the main app is not affected; it can just carry on and launch the helper process again. If one portion of your app is especially prone to crashing (perhaps it parses user input?), you could separate that out into a separate process, and now your app is more stable.<br /><br /><i>Privilege separation </i>is the ability to limit the access of a process. If your parser has a vulnerability that allows access to any portion of memory, a malicious user might be able to gain access to data meant to be secure, such as user passwords, and upload them to a server<sup><a id="ref2" href="#footnote2">2</a></sup>. On OS X, XPC services can also be given a more restrictive sandbox, such that the helper process would not even have access to the network. Even if there's a vulnerability in your parser code, blocking the ability of the parser to upload data to the network means that you've greatly limited the damage a malicious app can do.<br />&nbsp;</li><li><b>Third-party keyboards?</b><br />Users have long requesting support for third-party keyboards in iOS. One of my friends says that the main reason she won't get an iPhone is that she the&nbsp;<a href="http://www.swype.com/" target="_blank">Swype</a> keyboard is not supported on iOS.<br /><br />Third-party keyboards have always been a security concern, though. A keyboard has access to <i>every key you type</i>. This means it has access to every username, password, social security number, and credit card number the user types in <i>any</i>&nbsp;app. Apple has long prioritized privacy and security over user features. I've always assumed that this was simply the death knell of third-party keyboard support in iOS.<br /><br />However, if we've already added App Services and Sandboxing in iOS 8, then there might be a way forward. There might be a special type of app service for third-party keyboards. These keyboard services would run in a very restricted sandbox; they would likely have no access to network, location, contacts, photos, etc. It could not launch other app services. Without this access, even a malicious keylogging keyboard would have no way to report your data. With these restrictions, Apple might consider allowing third-party keyboards.<br /><br />I think a lot of people would be excited to see this in iOS 8. It's possible, though, that Apple might prove out app services in iOS 8 before adding keyboard support in a later release. I won't say that I <i>think</i>&nbsp;this one's going to happen at WWDC 2014—it probably won't. But I'll hope for it anyway.<br />&nbsp; </li><li><b>Healthbook</b><br />Pretty much every rumor for months has indicated that iOS 8 will include a <i>Healthbook</i> app. It will apparently be able to track various health related biometrics, such as activity, sleep quality, heart rate, blood pressure, etc. <br /><br />It's a cool idea. The main question is how the data will be collected. Some metrics (step count, etc.) can be inferred just by motion of the phone itself. The rumors indicate, though, that it will have far more data than that. A report <a href="http://9to5mac.com/2014/03/17/this-is-healthbook-apples-first-major-step-into-health-fitness-tracking/" target="_blank">from 9to5Mac</a> indicates that it will track metrics like "<i>heart rate, hydration, blood pressure, physical activity, nutrition, blood sugar, sleep, respiratory rate, oxygen saturation, and weight.</i>" Some of these could perhaps be entered manually by the user, but if this is going to have any impact at all, most of this data collection has to be automatic.<br /><br />The rumored "iWatch" might be able to provide more of this data, as it would have direct skin contact. However, I think it's unlikely that any wearable tech will be announced at WWDC. Without that, I'm not sure how useful a Healthbook feature would be. If iWatch is to be released this fall, then perhaps Apple will refrain from announcing it at WWDC, but include Healthbook in iOS 8 when it ships this fall.<br /><br />Color me skeptical that we'll hear about Healthbook at iOS 8. I won't rule it out, but I'm skeptical. I just don't see how it can be useful without greater ecosystem support.<br />&nbsp;&nbsp;</li><li><b>Much improved javascript performance</b><br />Javascript performance is slower in third-party apps than in the native Safari app because the JIT compilation techniques used in Safari require write access to executable memory pages. This is considered a security concern in third-party apps, and thus JIT has been disabled there. I would be <i>very</i>&nbsp;surprised if this performance restriction is not removed in iOS 8 by means of out-of-process execution or rendering.<br /><br />I'm calling this one. It's coming.</li></ul></div><h3>Xcode and Developer Tools</h3><div>There are a <i>lot</i>&nbsp;of <a href="https://developer.apple.com/wwdc/schedule/labs/" target="_blank">TBA labs</a> on the Tools track. I think there will be some really exciting stuff here.&nbsp;I keep a fairly close eye on the clang commit logs, though, and I've got a couple predictions.<br /><br /><ul><li><b>Better formatting</b><br />The <a href="http://clang.llvm.org/docs/ClangFormat.html" target="_blank"><i>clang-format</i>&nbsp;project </a>is an automatic code formatting tool built on clang libraries. While Xcode's code formatting ability is passable right now, they're nothing spectacular. In particular, Xcode often does really dumb things with multi-line dictionary literals or array literals. I'm hoping we'll see that improved in Xcode 5.2 (or whatever's coming next.)<br />&nbsp;</li><li><b>Fewer tolls at our toll-free bridges</b><br />ARC has done lots of wonderful things, but one thing it <i>hasn't</i>&nbsp;done is simplified toll-free bridging. Instead, we often see <code>(__bridge MyFoo*)</code> casts to specifically indicate that we don't want any memory management to happen. I think we'll see many of those casts disappear in common cases.<br />&nbsp;</li><li><b>Better Beta Distribution tools</b><br />Earlier this year, Apple acquired Burstly, the owners of TestFlight. TestFlight is a very widely-used service for distributing and managing beta versions of in-development apps. Shortly after the purchase, their Android platform was shut down. Beta distribution is a pain on both iOS and OS X right now. It involves collecting device UDIDs, managing provisioning profiles, etc. On Android, by contrast, users can be added to a beta simply by adding them to a Google Group. This is an area where developers are often frustrated with the Apple platform, and it's a great opportunity for them to win back some developer goodwill. I'm hopeful we'll see something exciting.<br />&nbsp;</li><li><b>More improvements around Modules</b><br />Last year, Apple introduced <a href="http://stackoverflow.com/questions/18947516/import-vs-import-ios-7">modules</a> as a compiler feature. They enable the <code>@import</code> keyword, enable auto-linking of frameworks, and can make compilation times <i>much</i> faster. However, so far it's only been available for importing system frameworks. I've seen some commits on the Clang logs indicating that support for user modules is under development. I don't know if it will be ready for WWDC or not, but I'd love to see what the new possibilities here are.<br />&nbsp;</li><li><b>Mogenerator (please?)</b><br /><a href="https://github.com/rentzsch/mogenerator" target="_blank">Mogenerator</a> is a great tool for working with Core Data. It automatically generates property declarations for you in .h and .m files, and then creates <i>subclasses</i>&nbsp;of those auto-generated classes&nbsp;for developer customization. If you're not using it, you absolutely should be. Even <a href="http://rentzsch.tumblr.com/post/82453434093/apple-claims-mogenerators-methods" target="_blank">some Apple teams</a> use it internally.<br /><br />Frankly, it seems insane that something like this isn't part of Xcode already.</li></ul><div>Beyond that, I really have no idea. I don't think we'll see Xcode plug-ins this year; I think when they do that it will be a major revision number, and I don't think they're ready to call this Xcode 6. Is that a silly reason to hold back a feature? Probably, but I stand by my guess.</div></div><h3>iCloud</h3><div>Last year, I predicted that most of the iCloud talk at WWDC would be about how they've fixed all the bugs (especially with the iCloud-Core Data integration), and would not be announcing new features. Well, here's a quote from last year's Platforms State of the Union:<br /><blockquote class="tr_bq">So this is an area that we have decided to not implement any new features this year but instead to focus on reliability and quality.</blockquote>Nailed it. This year, I think we'll be back in feature land. I really have no solid evidence on any of the following points; they're just guesses and wishes, not predictions.<br /><br /><ul><li><b>Improved Photo Stream service</b><br />It's been said by many people: Instead of all the photos living on your device, with only the most recent ones living on Photo Stream, it should be the other way around. iCloud should store <i>all</i>&nbsp;my photos, and my phone should be able to download them on demand. Server storage is incredibly cheap these days; it seems like Apple should be able to do something better than what they've got right now.<br />&nbsp;</li><li><b>Larger quotas</b><br />Speaking of server storage costs, I hope we see the free storage tier bumped up dramatically from the current 5GB. Device backups alone can take up the majority of the free 5GB tier; I've turned off iCloud Backup on one of my devices because I was running out of space. If "always backed up, all the time" is supposed to be one of the big features of iCloud Backup, then they need to offer more space.<br />&nbsp;</li><li><b>Server access</b><br />One of the problems with iCloud document storage is that developers have no external access to the data. For example, many users have asked us at Day One for a way to add journal entries online. With iCloud document storage, there's simply no way for us to do this. Third-party servers have no access to the user's iCloud storage.<br /><br />If Apple allows server access, expect to see server provisioning profiles as part of it. People will complain about it, but I don't see Apple allowing this any other way.</li></ul></div><h3>Other</h3><div>A few other predictions that just didn't fit anywhere above:</div><ul><li><b>Improved Maps w/ Transit (iOS and OS X)</b><br />In the Keynote session, they'll probably show off some fancy updates to Maps, including support for mass transit schedules. They won't cut off the existing transit apps added in iOS 6, but for many users, this will be much simpler.<br />&nbsp;</li><li><b>App Rentals</b><br />A couple years ago, references to "App Rentals" were found in iTunes. I'd love to see developer able to mark their app as available for rent. A user might rent the app for 1 week at a cost of $0.99. After that period, the app would remain installed, but upon opening it the user would be informed that their rental period had expired. They could choose to rent it again, purchase the app, or exit.<br /><br />It would be opt-in by the developer, of course, but I think most developers would be extremely excited for this. If developers were allowed to limit the number of times an app could be rented, it could serve as an inexpensive "trial period" for users. I've been hoping for this ever since it was discovered, but who knows if we'll finally see it in iOS 8 or not.<br />&nbsp;</li><li><b>Something else</b><br />A new class for OS X and iOS whose SHA-1 hash is <code>c1516c6879792c45fac4867d9a66b73e7d2514f9</code><sup><a id="ref3" href="#footnote3">3</a></sup>. (<b>Post-WWDC update:</b> The class is "WKWebView", which could be found in the open-source WebKit repositories weeks before WWDC.)</li></ul><br /><hr/><div style="font-size: small"><span id="footnote1">1</span>: Of course, not all of those sessions will contain earth-shattering revelations; pretty much any mention of the word "new" is enough to redact the entire session until after the keynote. And yet, somehow "What's New in Foundation Networking" slips through unredacted. Not sure what's up with that.<a href="#ref1">↩</a><br /><br /><span id="footnote2">2</span>: This is perhaps a lesser concern on iOS, simply due to the difficulty of getting malicious payloads into the target app and the inability to spawn separate processes. Nevertheless, it's one that should not be simply ignored.<a href="#ref2">↩</a><br /><br /><span id="footnote3">3</span>: Yes, I'm totally taunting you here. The information is publicly available, and has been for weeks, but I haven't seen anyone else discussing it. But I don't want to be the one to spoil Christmas morning! The name of this class isn't actually all that exciting, but I think the technology behind it will make a lot of people happy. <a href="#ref3">↩</a><br /></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-60492045037826944322014-04-26T00:52:00.003-07:002014-04-26T00:52:41.468-07:00Mormon Questions: Mistaken RevelationMormons<sup><a id="ref1" href="#footnote1">1</a></sup> believe that we learn truth not only through scripture, but also through direct personal revelation from God. This is <i>essential</i> to our religion. Missionaries invite the people to seek divine confirmation that their message is true from the very first meeting. We teach the importance of personal revelation in Sunday School and in youth Primary classes. The Book of Mormon itself includes this invitation in its concluding chapter:<br /><br /><blockquote class="tr_bq" style="background-color: #FFFFE0; border-radius: 4px; padding: 10px;">And when ye shall receive these things, I would exhort you that ye would ask God, the Eternal Father, in the name of Christ, if these things are not true; and if ye shall ask with a sincere heart, with real intent, having faith in Christ, <b>he will manifest the truth of it unto you, by the power of the Holy Ghost</b>. (<a href="https://www.lds.org/scriptures/bofm/moro/10.4" target="_blank">Read in context</a>)</blockquote><br />And yet, personal revelation is a difficult doctrine. By its very nature, it is individual and non-verifiable. I cannot experience what you have experienced; I cannot show you what revelation feels or sounds or tastes like. I can tell you about my own experiences, but since God communicates to each person in their own way, my experience may not be relevant to you.<br /><br />This means, of course, that I cannot verify that what you experienced is a revelation. Wishful thinking can easily be mistaken for revelation, as can trepidation or nervousness. The human mind has all sorts of ways to convince itself of things that may not actually be true. The doctrine of personal revelation is not one of pristine, unambiguous communication.<br /><br />How can you know, then, if a supposed revelation really comes from God? How can we distinguish divine direction from internal monologue? What about other religions that claim divine revelation from a different source?<sup><a id="ref2" href="#footnote2">2</a></sup><br /><br />The answer to misinterpreted revelation is, quite simply, practice. Like most learned skills, we'll probably make a lot of mistakes at first, and practice is the only way to figure it out. Fortunately, we actually have ample opportunity to do so. Each of us has a conscience, an internal sense for right and wrong. Mormons believe that this sense actually has a divine origin, known as the Light of Christ. When we listen to our conscience, we are actually learning to receive simple revelation. The same principles involved in recognizing right from wrong <i>by instinct</i> are used in discerning revelation. In the same way that sharing or sticking up for others just "feels right," revelation from God also "feels right."<br /><br />Of course, none of us is perfect at following our conscience either. We've all experienced that moment when you realize that you made the wrong choice. That discomfort is instructive too; it teaches us to recognize correction. If we continually ignore our conscience, though, we'll eventually diminish our ability to recognize its guidance.<br /><br />A key principle in recognizing true revelation, then, is <i>consistently following your conscience</i>. As you do so, you'll become more sensitive to its instruction. This will help you recognize other forms of revelation.<br /><br />More specific revelation is available when we seek for it. Prayer at its best is simply communication with God. <i>Two-way </i>communication. Though it's easy to fall into a routine of saying the same repeated phrases every time we pray, prayer should resemble a conversation more than a monologue. Prayer should include questions, and silent time to ponder as we seek to discern revelation in response to those questions. God does answer.<br /><br />This pattern of revelation continues; as we attune ourselves more toward God and follow his guidance more and more closely, we will have access to more specific and more frequent revelation. Our ability to communicate with God will increase, as will our ability to recognize it.<br /><br /><blockquote class="twitter-tweet" lang="en"><a href="https://twitter.com/bjhomer">@bjhomer</a> I wouldn't think so, but what does that mean for those that misinterpret his messages to them?<br />— Heath Borders (@heathborders) <a href="https://twitter.com/heathborders/statuses/455796808762269696">April 14, 2014</a></blockquote><script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script><br /><br />I am hesitant to judge the motivation and experiences of someone I don't know. I do not believe God would give one person truth and another a lie; all revelation from God is true and consistent. God might, however, guide a person (via revelation) to a best available option, even if none of those options is the ideal.<sup><a href="#footnote3" id="ref3">3</a></sup> Some who claim revelation may simply be mistaken, either through their own wishful thinking or by the deceptive action of another. And yes, some of them might simply be lying, claiming revelation in order to attract attention and exploit followers. Most people who seek revelation are sincere, though.<br /><br />My experience in this faith, though, has shown me that many, many people receive compatible instruction through revelation. There <i>is</i>&nbsp;a universal truth, being revealed to many individuals independently. Further, revelation often gives us information we could not have known otherwise, giving us insight into the needs of those around us or explaining things we did not know. Learning to accurately recognize revelation takes time and practice, and we all make mistakes, but the principle is nonetheless true.<br /><br />Remember, though, that revelation is not something only for a few elite. Everyone receives it in at least small measure through our conscience. The Book of Mormon teaches this:<br /><br /><blockquote class="tr_bq" style="background-color: #FFFFE0; border-radius: 4px; padding: 10px;">But behold, that which is of God inviteth and enticeth to do good continually; wherefore, every thing which inviteth and enticeth to do good, and to love God, and to serve him, is inspired of God. (<a href="https://www.lds.org/scriptures/bofm/moro/7.13?lang=eng" target="_blank">Read in context</a>)</blockquote><br />Whether or not you believe in God, choose to do good. If I'm right, it will increase your ability to recognize God's voice. If I'm wrong, it will still make the world a better place. Either way, choose Good.<br /><br /><hr />I'd love to hear your questions or thoughts about this article, or any other questions you have about Mormons. Find me on Twitter (<a href="http://twitter.com/bjhomer" target="_blank">@bjhomer</a>), or send me an email (<a href="mailto:bjhomer@gmail.com">bjhomer@gmail.com</a>).<br /><br />Also, I promise I've got some technical posts in the pipeline too. I haven't forgotten.<br /><br /><hr /><div style="font-size: small"><span id="footnote1">1: More acccurately, "members of the Church of Jesus Christ of Latter Day Saints". Though I don't find the term offensive, I think calling us "Mormons" is misleading to those unfamiliar with our faith. While belief in the Book of Mormon is a <i>unique</i> feature of our teachings, neither the Book of Mormon nor Mormon-the-person is a central figure of my faith, any more than rubber-band overscrolling is the core of the iPhone experience. It's a unique and identifying feature, but hardly the main point. Mormons follow, preach, and teach about Jesus Christ. All those other things just point us to him.<br /><br />Yes, I will probably mention this in every "Mormon Questions" post. It's important to me.</span><a href="#ref1" title="Jump back to footnote 1 in the text.">↩</a><br /><br /><span id="footnote2">2: There are actually surprisingly few Christian religions that preach modern revelation. Many teach that the Bible contains all we ever need to hear from God. Some teach that God can influence people in undefined ways to do good, but stop short of acknowledging specific revelation. I believe most non-Christian religions either teach that revelation has ceased, or concern themselves more with morals and practices than with revelation. I am not aware of any other religion teaching that God gives revelation today exactly as he did in Biblical or other ancient times. (I admit, though, that I am not familiar with <i>all</i>&nbsp;world religions. Surely such religions exist; I am simply unfamiliar with them and thus cannot address their specific claims.)</span><a href="#ref2" title="Jump back to footnote 2 in the text.">↩</a><br /><br /><span id="footnote3">3: For example, this might happen in areas where Christianity is virtually unknown. God might still reveal to someone the importance of following one's conscience, or guide someone to an established religion in that area that would teach&nbsp;<i>many&nbsp;</i>correct principles until such time as His authorized church was available there.</span><a href="#ref3" title="Jump back to footnote 3 in the text.">↩</a><br /></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-50290013064403957332014-04-20T00:02:00.000-07:002014-04-20T00:02:00.155-07:00Death and ResurrectionToday is Easter. Let's talk about it.<br /><br />Nearly a year ago, my grandfather passed away. It was not unexpected—he'd been in pain and mostly unable to move out of his chair for months. He frequently said that he was ready to die, but just didn't know <i>how</i>. When the time finally came, we were relieved for him and for my grandmother.<br /><div class="separator" style="clear: both; text-align: center;"><br /></div>His passing was happy, and yet sad. We'd known it was coming, were relieved when it happened, and yet we still cried. We cried because my children wouldn't get to know him, wouldn't hear his stories, wouldn't enjoy his rich singing voice. We cried for the loneliness my grandmother would endure after his passing. We cried for the loss and separation we each felt in our hearts.<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="http://2.bp.blogspot.com/-pmHQvyP_nqQ/U1NfgTO4qsI/AAAAAAAAAsM/p8H7t8S_3a0/s1600/Harold+Military.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-pmHQvyP_nqQ/U1NfgTO4qsI/AAAAAAAAAsM/p8H7t8S_3a0/s1600/Harold+Military.jpg" height="320" width="216" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Harold during World War II</td></tr></tbody></table><div>Most of us have had some experience with death in one way or another. Some have had <i>far more</i> than their share. The loss we feel when someone we love dies is real and painful. It touches us deeply.</div><div><br /></div><div><i>But it is not permanent. Death is not the end.</i></div><div><br /></div><div>Easter is the celebration of Jesus Christ's resurrection. Three days after his death, his friends and followers went to his tomb and found it empty. Perplexed, they wondered if his body had been moved to another location, or perhaps been taken by vandals.&nbsp;</div><div><br /></div><div>But no, his body was not taken away. He was <i>risen, </i>resurrected. He was <i>alive again</i>. He visited his friends, showed them that he was again a living soul. He ate with them, let the touch his body. This was no mere spirit—Jesus Christ had literally risen from the dead. Something new, something none of them had seen before. Imagine the wonder you might feel—the shock, disbelief, or amazement.</div><div><br /></div><div>This resurrection was not limited to Jesus Christ. He was the first, the evidence of death's defeat. But he was not the last. Indeed, Christ promised that through his victory,&nbsp;<i>all</i>&nbsp;would rise again. All of us. Each one of us will live again, regardless of our beliefs or our actions. Resurrection is a gift freely given to the entire human race.</div><div><br /></div><div><i>This</i> is why we celebrate Easter. My grandfather will live again. You and I will live again. Your parents will. All of us will. We need not fear death, for it is not the end. Is there a better reason to celebrate? Death, the universal enemy of man, is only a temporary rest stop in our eternal existence. Easter is a day of Hope, of rejoicing and happiness. Christ lived again, and because he did, we all will. Should not this be the very greatest of holidays?<br /><br />So today, on Easter, take a moment and consider it. What would Resurrection mean to you?<br /><br /><iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/_S3TI4bYerU" width="560"></iframe><br /><br /><br /></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-22331237860448371652014-04-09T09:23:00.000-07:002014-04-11T07:17:54.122-07:00Mormon Questions: Why THIS church?I'm a member of the Church of Jesus Christ of Latter-Day Saints. That's a long name, so in the interest of efficient communication most people just call us Mormons<sup id="ref1"><a href="#footnote1" title="Jump to footnote 1">1</a></sup>. Last weekend was the church's semi-annual&nbsp;<a href="https://www.lds.org/general-conference/sessions/2014/04?lang=eng" target="_blank">General Conference</a>. It consists of five 2-hour sessions, each broadcast to church meetinghouses worldwide and streamed live on the internet. Speakers chosen from church leadership select their own topics, usually focused on some aspect of Christ's life or on how we can apply his teachings and doctrine to our own lives today.<br /><br />This conference is a special time for us; we believe the church is led by literal prophets and apostles, authorized and ordained just like the apostles during Christ's life. Getting messages from all of them, in one weekend, is a feast for the spiritually inclined. You might think of it somewhat like a weekend of spiritually-focused TED talks.<br /><br />During the conference I was&nbsp;tweeting things that stood out to me. This led to a few discussions with my followers, which I was happy to entertain.<br /><blockquote class="twitter-tweet" lang="en">If you have questions about Mormons or my beliefs, feel free to ask. I’ll answer what I can now, though sometimes 140 characters is hard.<br />— BJ Homer (@bjhomer) <a href="https://twitter.com/bjhomer/statuses/452502214334902272">April 5, 2014</a></blockquote>I answered the questions as well as I could, and had some great conversations. Some questions, though, are difficult to answer in 140 characters, so I wanted to revisit a few of those here over the next few days and provide more complete answers.<br /><br /><hr /><blockquote class="twitter-tweet" data-conversation="none" lang="en"><a href="https://twitter.com/bjhomer"><br />@bjhomer</a> Genuinely curious: why have faith in that notion of God+teachings instead of some other one (Zoroastrianism, Hinduism, etc)?<br />— Andy Matuschak (@andy_matuschak) <a href="https://twitter.com/andy_matuschak/statuses/452534846338772992">April 5, 2014</a></blockquote>The short answer to this question is simply "Because God told me so." Mormons believe that everyone is capable of receiving direct personal revelation, and that God expects us to use it.<br /><br />On this topic of personal revelation, it's important to understand our relationship with God. God cares deeply about us, because we are literally his children. Each of us lived with him as a spirit, his spirit children, before we were born here on Earth. Revelation from God, then, is literally communication between parent and child. He is eager to help us learn.<br /><br />You and I adjust our communication according to the person we're speaking with. A conversation between myself and a technical co-worker sounds very different from a conversation with my wife, and both are different from a conversation with a non-technical family friend, or a conversation with my children. We all adjust the content and manner of our communication according to the understanding and needs of the recipient.<br /><br />God does the same when he speaks to us. Because he wants us to develop and exercise faith, he rarely speaks to us face-to-face<sup id="ref2"><a href="#footnote2" title="Jump to footnote 2">2</a></sup>. Instead, he speaks to us through various other mechanisms. He can guide our thoughts, touch our emotions, and influence our dreams. He can give us an unshakable feeling that something is wrong, or that something is right. He can remind us of things we have learned before, and plant thoughts we've never before considered.<br /><br />All of these mechanisms, and many others, are available to God as he communicates with us. And because each of us is unique, he tailors his revelation to each of us according to our unique abilities to learn and our skill in perceiving his communication. For me, revelation often comes as new insights into some topic, accompanied by powerful feeling that what I'm considering is right, that it <i>just makes sense—how could it be any other way</i>? Sometimes, it may come as a warm feeling in the heart, a comfort and peace that things are just right. Infrequently, I've had dreams that seemed to have special significance to them; they gave me new understanding of a situation.<br /><br />Because God's revelation is uniquely suited to each individual, it cannot be shared. I can tell you what I've learned, but I cannot prove my revelation to you. Each person has the opportunity to seek revelation from God on their own, and receive the same confirmation. This invitation is given in both the Bible and the Book of Mormon:<br /><blockquote class="tr_bq"><b>New Testament -&nbsp;<a href="https://www.lds.org/scriptures/nt/james/1.5" target="_blank">James 1:5</a></b><br />If any of you lack wisdom, let him ask of God, that giveth to all men liberally, and upbraideth not; and it shall be given him. &nbsp;</blockquote><blockquote class="tr_bq"><b>Book of Mormon -</b>&nbsp;<a href="https://www.lds.org/scriptures/bofm/moro/10.4" target="_blank"><b>Moroni 10:4</b></a><br />And when ye shall receive these things, I would exhort you that ye would ask God, the Eternal Father, in the name of Christ, if these things are not true; and if ye shall ask with a sincere heart, with real intent, having faith in Christ, he will manifest the truth of it unto you, by the power of the Holy Ghost.</blockquote>So, I believe that my church teaches the truth about God because I've asked him in prayer if that is so, and I believe he has answered through direct revelation that it does. It really comes down to that, in the end.<br /><br />Andy had another question at the end of our conversation:<br /><blockquote class="twitter-tweet" lang="en"><a href="https://twitter.com/bjhomer">@bjhomer</a> When you do, can you try to answer: “it feels right” is unacceptable in other areas of study; why’s it a valid justification here?<br />— Andy Matuschak (@andy_matuschak) <a href="https://twitter.com/andy_matuschak/statuses/452542538314813440">April 5, 2014</a></blockquote>"It feels right" is appropriate because revelation is <i>communication</i>, not scientific inquiry. We are not <i>studying</i> God, we are talking to him. Talking <i>with</i>&nbsp;him.&nbsp;Scientific<sup id="ref3"><a href="#footnote3" title="Jump to footnote 3">3</a></sup> inquiry comes, if appropriate, as we choose whether to act on the guidance he gives us. When we act in faith on received revelation, we make a hypothesis (of sorts) that acting on that communication will produce some desired outcome. After doing so, we can evaluate the results. That process will, I believe, validate the initial exercise of faith.<br /><br />This principle of acting in faith is an inherent part of our relationship with our Father. He wants it that way, it seems; there are things we can learn when forced to act in faith that we cannot learn any other way<sup id="ref4"><a href="#footnote4" title="Jump to footnote 4">4</a></sup>.<br /><br />"It feels right" is also appropriate simply because that's often how God speaks; it is not our privilege to dictate how he will communicate. For most of history, a rigorous scientific method for discovering truth was unknown. Even today, there are many people throughout the world who lack the training to adequately seek truth through careful examination of hypotheses and control groups. Our Father is not just interested that <i>somebody</i>&nbsp;know the truth; he wants it available to <i>all</i>&nbsp;of us.<br /><br />God speaks the way he does precisely so that we can all hear his voice, no matter who or where we are.<br /><br /><hr />I'd love to hear feedback on this article. I'll respond most quickly on <a href="http://twitter.com/bjhomer" target="_blank">Twitter</a>, but you can also email me at <a href="mailto:bjhomer@gmail.com">bjhomer@gmail.com</a>.<br /><br />If you have other questions about my faith that you'd like to see answered, please let me know. I've got a couple more posts already planned, and I'll keep writing as long as there are questions.<br /><br /><hr /><span id="footnote1" style="font-size: small;">1</span><span style="font-size: small;">: The common use of "Mormon" as a reference to the church is derived from our acceptance of The Book of Mormon as an additional book of canonical scripture alongside the Bible. Despite the nickname, we follow and worship Jesus Christ, not Mormon or any other person.</span><a href="#ref1" style="font-size: small;" title="Jump back to footnote 1 in the text.">↩</a><br /><span style="font-size: small;"><br /></span><span style="font-size: small;"><span id="footnote2">2</span>: Face-to-face appearances <i>have</i>&nbsp;occurred, both anciently and modernly, but they are rare. They carry with them an increased responsibility upon the recipient—when you have that kind of knowledge that God exists, he expects more of you. Excuses hold less weight when you absolutely <i>know</i> better.<a href="#ref2" title="Jump back to footnote 2 in the text.">↩</a></span><br /><span style="font-size: small;"><br /></span><span style="font-size: small;"><span id="footnote3">3</span>: I use the term "scientific" here quite loosely, as the inherent nature of personal revelation makes it impossible to construct any sort of control group or independent verification. Everyone can have the experience of communicating with their Father in Heaven, but each person's experience will be unique and personal.<a href="#ref3" title="Jump back to footnote 3 in the text.">↩</a></span><br /><span style="font-size: small;"><br /></span><span style="font-size: small;"><span id="footnote4">4</span>: We believe that a primary purpose of our time here on Earth is to develop attributes and learn skills that we simply could not learn while constantly in the presence of God. Much like some baby birds learns to fly only when kicked out of the nest, there are some aspects of us that can only grow while away from God's immediate presence.<a href="#ref4" title="Jump back to footnote 4 in the text.">↩</a></span><br /><script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-91590650810102075672013-10-28T21:57:00.001-07:002013-10-31T08:38:55.435-07:00Will code for Obduction pledges<br /><div>Cyan, the company behind Myst and Riven, is creating a new game. It's in the same style as their previous games, but in a new world, with a new storyline, and in full 3D. It's called <a href="http://obductiongame.com/" target="_blank">Obduction</a>, and it looks amazing. I want this game.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="http://obductiongame.com/logo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="http://obductiongame.com/logo.jpg" width="640" /></a></div><div><br /></div><div><br /></div><div>I grew up playing the original Myst series, and I'd love to share a new experience like this with my children. That can only happen, though, if <a href="http://www.kickstarter.com/projects/cyaninc/obduction" target="_blank">Cyan's Kickstarter campaign</a> succeeds. They're trying to raise $1.1 million to help fund the game; right now they're a bit over halfway there. I <i>really</i> want this Kickstarter campaign to succeed. You should go contribute. Please, help out with this amazing project.</div><div><br /></div><div>If that plea is not enough, though, let me give you an additional reason to contribute.</div><div><br /></div><div><b>If you pledge $50 to the Obduction kickstarter, I will work one hour</b> on whatever iOS or Mac software project you choose. If you pledge $100, I will work two hours. If you pledge $500, I will work 10 hours. &nbsp;This is <i>far</i> below my usual rate; it's a fantastic deal.</div><div><br /></div><div>I'll review code, write unit tests, add new features, or fix bugs. If we can work out travel arrangements, I'll come give in-person trainings. (I live in Utah.) You can have me work on your own project, or on an open source project, or something else. I'm an expert in iOS and Mac development. I can also offer training on&nbsp;<span style="font-family: Courier New, Courier, monospace;">git</span><span style="font-family: inherit;">, if that's of interest. If you have some other idea, send me an email and let's work something out</span><span style="font-family: inherit;">.</span></div><div><span style="font-family: inherit;"><br /></span></div><div><span style="font-family: inherit;"><b>How to pledge</b></span></div><div><span style="font-family: inherit;">Cyan doesn't actually have a $50 pledge level on Obduction. Pick any reward level below what you're wanting to pledge; once you've selected a reward level, you can add additional money to your pledge. Top it off to the next $50 increment. If you've already backed Obduction, increase your pledge by the amount corresponding to the work you want done.</span></div><div><br /></div><div><b>Who am I?</b></div><div>I'm a developer on <a href="http://dayoneapp.com/" target="_blank">Day One</a>, the best journal app for iOS and Mac. Day One for Mac was named Apple's Mac App of the Year in 2012. Right now it's the #15 paid app in the U.S. Mac App Store. The iOS app was one of 10 apps featured in the Apple's <i>5 Years of the App Store</i>&nbsp;celebration in Summer 2013.</div><div><br /></div><div>I have over <a href="http://stackoverflow.com/users/100478/bj-homer" target="_blank">23,000 reputation</a>&nbsp;on StackOverflow.com. I'm the author of <a href="https://github.com/instructure/CKRefreshControl" target="_blank">CKRefreshControl</a>, and <a href="https://github.com/bjhomer/HSImageSidebarView" target="_blank">HSImageSidebarView</a>. I post lots of code-related stuff on Twitter (<a href="http://twitter.com/bjhomer" target="_blank">@bjhomer</a>). I'm the one friends turn to when they need Objective-C help.</div><div><br /></div><div>Of course, I have a full-time job and a family, so I have to limit my offer. &nbsp;I will make up to 20 hours per month available to Obduction backers. These hours are available on a first-come basis. If you are interested, pledge your support to the Obduction campaign, then send me an email at bjhomer@gmail.com.<br /><br /><b>UPDATE:</b><br />The first month of work has been claimed! If you back Obduction now, I'll start on your work sometime in late November.</div><div><br /></div><div><span style="font-size: x-small;">* Yes, this offer was inspired by <a href="http://adammorganauthor.com/2013/10/23/yes-i-will-read-your-script-and-give-you-notes/" target="_blank">Adam Morgan's offer</a> to read film and TV scripts in exchange for Obduction pledges. I think it's a fantastic idea.</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;"><b>Caveats:</b></span></div><div><span style="font-size: x-small;">I can't work on anything that would directly compete with Day One, my employer. This should not come as a surprise to you. &nbsp;I may turn down work for other reasons as well, but hopefully that won't be necessary.</span></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-72906557341219275022013-06-09T17:59:00.001-07:002013-06-09T17:59:11.830-07:00Anticipating WWDC 2013WWDC 2013 is a little over a week away. We already know a few things; iOS 7 and OS X 10.9 will be unveiled, and iOS will be getting a visual overhaul. Here's what I'm anticipating.<br /><h4>iOS 7</h4><div><ul><li>Updated design.</li><li>Better inter-app integration. This will probably be based on the Remote View Controller technology used internally in iOS 6, but will probably not be as generic as allowing an app to expose any arbitrary view controller for presentation by another app. Rather, I expect we'll see targeted use cases: an app may be able to specify a controller to be used for accepting files from other apps, or to be used for providing access to files found in other apps.</li></ul></div><h4>OS X 10.9</h4><div><ul><li>Siri support and Maps apps</li><li>MapKit APIs for developers</li><li>Re-redesigned Safari web inspector. (You can already play with this in the Webkit Nightly; it's <i>much</i> improved over the Safari 6 design.)</li><li>Better full-screen app support.</li><li>The biggest question: What will it be named? <a href="http://www.macrumors.com/2013/06/07/wave-themed-os-x-banner-goes-up-at-moscone-west-for-wwdc-2013/" target="_blank">Sea Lion?</a></li></ul></div><h4>Xcode</h4><div><ul><li>Modules, a new language feature designed to significantly improve compiler performance. Doug Gregor talked about this at the <a href="http://llvm.org/devmtg/2012-11/#talk6" target="_blank">2012 LLVM developer's meeting</a>, so it's a fairly safe bet.</li><li>Big improvements for Auto Layout in Interface Builder. I'm not sure exactly what a better interface for Auto Layout would look like, but it's way too easy for constraints to get lots in the shuffle as things currently stand.</li><li><i>Lots</i>&nbsp;of improvements to Xcode. I just don't know what they all are. Maybe enough to call it Xcode 5?</li></ul></div><h4>iCloud</h4><div><ul><li>Lots of talk about how they've fixed all the problems.</li><li>More ancillary services (Photo Stream improvements, etc.)&nbsp;</li><li>No major feature changes to the developer platform; just lots of bug fixes.</li></ul></div><h4>Hardware</h4><div><br /><ul><li>Spec bumps for MacBook Pro line. Haswell processors, longer battery life.</li></ul></div><h4>New Platforms</h4><div>There are a lot of things pointing toward a new platform. The number of "To Be Announced" sessions on the schedule is a big one, and <a href="https://twitter.com/bjhomer/status/341687866860126208" target="_blank">as I noted on Twitter</a>, Apple's expecting a lot of people for some of those sessions. This screams "Big new thing that <i>everyone's</i> going to want to see". I'm hoping for third-party AppleTV apps, but there are the "iWatch" rumors too, so who knows. Regardless, I'll be very surprised if there's no new platform for third-party apps.<br /><br /><br />I should note that with the exception of modules in Xcode, I have no particular inside sources for any of the above predictions. I don't <i>know</i>&nbsp;anything. This is just based on rumors and my own feelings.</div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-73269706816363899052013-05-06T21:45:00.003-07:002014-05-30T11:33:06.541-07:00What AppleTV could bePeople have been hoping for an App Store for AppleTV for a while. Every year before WWDC, we hear rumors of what might be happening on that platform.<br /><br />I want to talk about what it <i>could</i>&nbsp;be.<br /><br />Rumors about a Apple TV set talk about an app store for the platform. But if the new TV won't connect to your existing DVD player or cable box, <i>nobody's going to buy it</i>. You have to address this problem.<br /><br />Home entertainment systems are terribly broken right now. Every new device you connect brings with it another remote control. Each one looks about the same; a number pad, some arrows, and a host of buttons like "Audio" and "Info" that nobody can really explain. They all connect to a custom on-screen menu, which never looks great and is different from every other device connected to the TV. It's a mess of inconsistency.<br /><br />Imagine a new AppleTV. It has the same functionality as the current AppleTV, but on the back are a series of HDMI input ports. When you plug in your DVD player, a new "app" shows up on the AppleTV main menu for the DVD player. You open the DVD player app, and you can control the entire DVD player right from that app, using the same AppleTV remote you were already using. You plug in your Wii U, a "Wii" app shows up on the menu that lets the Wii interface takes over the full screen. There you are, playing your Wii on your AppleTV.<br /><br />The AppleTV home screen becomes the TV's input selector. Instead of repeatedly pressing the "TV/Video" button on your remote, you just choose the input right on the AppleTV home screen. It's graphical and friendly, and your grandma can use it.<br /><br />In order for this to work, the AppleTV would need to know what to display for each input source; each device needs a corresponding AppleTV app. For some devices (e.g. game consoles), this app would do little more than provide a home screen icon, and display full-screen video from the device. For other devices (e.g. DVD players), the app would implement two-way functionality with the device to allow the user to control it with the AppleTV app. Conveniently, the HDMI spec already includes a Consumer Electronics Control ("CEC") connection that allows for two-way communication; no additional cables needed.<br /><br />When a new device is connected, the AppleTV would need to query the device to find out which app to install. Perhaps the device could return an App ID that the TV would install, or perhaps it would look things up by device model, just like how OS X installs printer drivers automatically on demand.<br /><br />Even without a built-in App Store, if Apple could save me from the remote control explosion I have right now, I'd buy it. This would make the AppleTV the hub of the family room electronics setup. A built-in app store would only make it that much more popular, and I think that's coming too. Imagine, the next Nintendo or Sega could simply ship dedicated controllers that connect via Bluetooth, and have no other hardware costs. You could build an entire platform on AppleTV.<br /><br />Apple has an opportunity to build an entirely new platform. I hope that's what they're doing.<br /><br /><hr /><span style="font-size: small;">Of course, you could do most of this with a set-top box as well; it doesn't need to be a full TV set. You'd just have to increase the size of the box a bit to handle the various inputs. But you'd still have to deal with the TV's input switching mechanism, volume control, etc; I just don't think it would have the same appeal.</span><br /><span style="font-size: small;"><br /></span> <span style="font-size: small;">Tell me what you think; I'm &nbsp;</span><a href="http://twitter.com/bjhomer" style="font-size: small;" target="_blank">@bjhomer</a><span style="font-size: small;">&nbsp;on Twitter</span>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-35992724848991504542012-04-27T09:48:00.000-07:002014-04-20T20:02:43.897-07:00Javascript variable capture for Objective-C developersI've been doing a lot of work with Javascript in web views lately. I'm a total Javascript beginner, but something just clicked, so I thought I'd share.<br /><br />In Javascript, you'll often see things like this:<br /><pre><code>for (var i=0; i&lt;5; ++i) {<br /> var someString = strings[i];<br /><br /> button.onclick = (function (str) {<br /> return function (event) {<br /> alert(str);<br /> };<br /> })(someString);<br />}<br /></code></pre>You may be wondering why it couldn't just look like this:<br /><pre><code>for (var i=0; i&lt;5; ++i) {<br /> var someString = strings[i];<br /><br /> button.onclick = function (event) {<br /> alert(someString);<br /> };<br />}<br /></code></pre><br />There are two things at play here. The first is that for loops don't create a new lexical scope in Javascript. Only functions create scope. That is, this:<br /><pre><code>for (var i=0; i&lt;5; ++i) {<br /> var someString = strings[i];<br />}<br /></code></pre>is exactly equivalent to this:<br /><pre><code>var someString;<br />for (var i=0; i&lt;5; ++i) {<br /> someString = strings[i];<br />}</code></pre>Note that the same variable is reused in every iteration of the loop. At the end of the loop, `someString` will have the value assigned in the last iteration.<br /><br />The second thing going on is that when Javascript captures a variable in a function, it is captured by reference, not by copy. If you're familiar with Objective-C blocks, you could imagine that <em>every</em> variable you capture is <code>__block</code>-qualified. If you create a bunch of anonymous functions (or closures, or blocks) inside a loop, any variable they capture will always have the value as of the last iteration of the loop.<br /><br />In Objective-C, it would look something like this. (Remember, every variable we capture in a block is going to be <code>__block</code>-qualified, to mimic Javascript's behavior.)<br /><pre><code>id reader = // some object<br />__block i = 0;<br />for (i=0; i&lt;5; ++i) {<br /> reader.onload = ^(NSData *fileData) {<br /> NSLog(@"i: %@", i); // Always logs '5'<br /> NSLog(@"the data: %@", fileData);<br /> };<br /> reader.readFile(someFile);<br />}</code></pre>To solve this, we need to pass things that we want to remain immutable (such as <code>i</code>) as arguments to a function. We can't just add another parameter to our <code>onload</code> block, because that's called by <code>reader</code>, which we'll assume we do not control. So instead, we introduce another block:<br />id reader = // some object<br /><pre><code>__block i = 0;<br />for (i=0; i&lt;5; ++i) {<br /><br /> reader.onload = (^(int param_i) {<br /> // Imitating JS here by making all captured variables __block<br /> __block local_i = param_i; <br /><br /> return ^(NSData *fileData){<br /> NSLog(@"i: %@", local_i);<br /> NSLog(@"theData: %@", fileData);<br /> };<br /> })(i);<br /> // Note that we immediately invoke the block. This returns<br /> // another block, which has captured the value of `i` at the<br /> // time we invoked our outer block. That returned block is <br /> // the one passed to 'reader.onload'.<br /><br /> reader.readFile(someFile);<br />}<br /></code></pre>Of course, in Objective-C, you'd never do that. But in Javascript, it's the easiest way to create a non-changing copy of a captured variable.BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-8564383112033375002012-03-15T22:29:00.002-07:002012-03-15T22:38:12.140-07:00Hiding the inputAccessoryView of a UIWebView<code>UIWebView</code> is a workhorse of a view. You can use it to display web pages, of course, but you can also use it to display locally-generated rich content.<br /><br />I was recently using <code>UIWebView</code> and the <code>contentEditable</code> attribute to implement a text field that allows inline images, etc. The fact that I'm using a web view, though, is an implementation detail; to the user, it should just look like any other text field.<br /><br />Unfortunately, <code>UIWebView</code> loves to show that little "Previous/Next" bar above the keyboard. It was useless and occupying valuable screen space, so I determined to find a way around it.<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="http://1.bp.blogspot.com/-OUpfk8iJVcM/T2LMNfEEyaI/AAAAAAAAAbc/D502bh67pIY/s1600/Screen+Shot+2012-03-15+at+11.07.21+PM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://1.bp.blogspot.com/-OUpfk8iJVcM/T2LMNfEEyaI/AAAAAAAAAbc/D502bh67pIY/s320/Screen+Shot+2012-03-15+at+11.07.21+PM.png" width="170" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">This bar is the enemy</td></tr></tbody></table>It was actually fairly simple; a <code>UIWebView</code> contains a <code>UIWebBrowserView</code>, a private class that does most of the real work. I discovered via <code><a href="https://github.com/nygard/class-dump" target="">class-dump</a></code> that it also implements <code>-(id)inputAccessoryView</code>, returning the bar in question. So at runtime, I create a subclass of <code>UIWebBrowserView</code> and override that method to return <code>nil</code>. Then I call <code>[self reloadInputViews]</code>, and I'm done.<br /><br />I've wrapped this up into a <code>UIWebView</code> category, which exposes a single property:<br /><code>@property (nonatomic, assign) BOOL hackishlyHidesInputAccessoryView;</code><br />You can find it <a href="https://gist.github.com/2048571">on gist</a>.<br /><br />Enjoy.<br /><br /><span style="font-size: x-small;">Note: This code has only been tested on iOS 5.1, and may not work on other versions of iOS.&nbsp;</span><span style="font-size: x-small;">I've filed rdar://</span><span style="font-size: x-small;">11040111 requesting a supported way to hide this bar. For now, though, this works, and it should fail gracefully if the internal <code>UIWebView</code> view&nbsp;</span><span style="font-size: x-small;">hierarchy changes. If Apple ever releases a supported method for hiding this bar, <i>please</i>&nbsp;<i>use that instead. </i>I only resort to hackery like this when I can find no other option.</span>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-79604199796246977732011-11-17T07:17:00.001-08:002013-02-15T10:13:14.459-08:00Detecting backspace in a UITextFieldI recently had need for a token field for iOS while implementing a "To:" field like the one in Mail.app. I ran into a problem, though.&nbsp;The token field consists of a label, some number of tokens, and a borderless UITextField at the end where the user can enter text for the next token. It looks something like this, if you'll forgive the ASCII art:<br /><br /><pre><code>-------------------------------------------------<br />| To: (token1) (token2) (token3) _____________ |<br />-------------------------------------------------<br /> ^ ^ ^ ^ ^<br />UILabel tokens UITextField<br /></code></pre><br />In Mail.app, if you're at the far left of the text field and hit the backspace key, the rightmost token will be highlighted. Another backspace deletes the token and puts focus back in the text field. But there's a problem. <code>UITextField</code> provides no way to detect a backward delete at the beginning of the field.<br /><br /><hr /><h3> Part 1: Discovery</h3><br />You'd think this would be simple, but it's not. Some of my early attempts included:<br /><ul><li>Implementing <code>-textField:shouldChangeCharactersInRange:replacementString:</code> in the text field's delegate and looking for an attempt change the range at (0,0). No dice—it's not called if the text isn't actually going to change.</li><li>Subclassing <code>UITextField</code> and overriding the <code>-deleteBackward</code> method (part of the <code>UIKeyInput</code> protocol, which <code>UITextField</code> conforms to via <code>UITextInput</code>). <code>-[UITextField deleteBackward]</code> is never called when the backspace key is pressed.&nbsp;<b>Update: As of iOS 6.0, this solution works. You don't need any of the crazy stuff below. But feel free to read if you're interested, or if you still need iOS 5 support.</b></li><li>Subclassing <code>UITextField</code> and overriding various methods declared in the <code>UITextInput</code> protocol, such as <code>-replaceRange:withText:</code>, <code>-setSelectedTextRange:</code>, etc. Surprisingly, none of these are called either—despite declaring conformance to the <code>UITextInput</code> protocol, it seems that UIKit doesn't actually use any of those methods when handling keyboard input.</li></ul>So, we've got a <code>UITextField</code> that claims to implement all these text-handling methods, and yet it doesn't seem to use them when handling keyboard input. It's probably forwarding them on to some other object, but how could we find out who that other object is?<br /><br /><strong>DTrace</strong>, of course.<br /><br />Using a boilerplate app containing a single UITextField, I pulled out Instruments and added a Trace instrument for <code>-[* delete*]</code>.<br /><div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-qeq6LSnawGw/TsUpCBxn4uI/AAAAAAAAAao/dObawPTD6ec/s1600/Screen+Shot+2011-10-29+at+11.07.23+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="128" src="http://1.bp.blogspot.com/-qeq6LSnawGw/TsUpCBxn4uI/AAAAAAAAAao/dObawPTD6ec/s320/Screen+Shot+2011-10-29+at+11.07.23+PM.png" width="320" /></a></div><br />That is, "Trace every ObjC call to any object where the selector starts with the word 'delete'." I launched the app and waited for things to quiet down, then tapped in the text field and hit the backspace key on the keyboard. Immediately, a few delete-related methods showed up, including this stack trace:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-LP7QvaO_ghk/TsUlsuEGemI/AAAAAAAAAag/_dInEAEr6nU/s1600/Screen+Shot+2011-10-29+at+11.14.27+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-LP7QvaO_ghk/TsUlsuEGemI/AAAAAAAAAag/_dInEAEr6nU/s1600/Screen+Shot+2011-10-29+at+11.14.27+PM.png" /></a></div><br />Why hello there, <code>UIFieldEditor</code> with a <code>UITextInputAdditions</code> category. We've been looking for you.<br /><br />I love DTrace.<br /><br /><hr /><h3> Part 2: Digging through the dump</h3><br />Okay, so we know there's something called a <code>UIFieldEditor</code>, and since <code>UITextField</code> wasn't involved at all in the above stack trace, we can guess that the field editor may be doing all of the heavy lifting. So let's look at <code>UIFieldEditor</code> a bit deeper.<br /><br />If we <a href="http://www.codethecode.com/projects/class-dump/">class-dump</a> <code>UIFieldEditor</code> in UIKit, we see that the first three methods in its method list are these:<br /><br /><pre><code>+ (void)releaseSharedInstance;<br />+ (id)sharedFieldEditor;<br />+ (id)activeFieldEditor;<br /></code></pre><br />So it appears that the <code>UIFieldEditor</code> receiving keyboard input is likely a shared object that is reused whenever the first responder needs keyboard input. Since there can only be one first responder at a time, there's probably no need for more than one <code>UIFieldEditor</code>.<br /><br />Class-dump also tells us that <code>UIFieldEditor</code> is a subclass of <code>UIWebDocumentView</code>. This is interesting, because a bit of time in DTrace will also confirm that <code>-[UITextField deleteBackward]</code> calls down to <code>[UIWebDocumentView deleteBackward]</code>. It looks like the field editor is a view that gets overlaid on top of text input views, and probably handles most of the text editing experience.<br /><br />So rather than subclassing <code>UITextField</code>, it looks like we really want to be subclassing <code>UIFieldEditor</code> if we want to do something special with <code>-deleteBackward</code>. <br /><br /><hr /><h3> Part 3: Dark Runtime Magic</h3><br />We've got two problems down the "Subclass UIFieldEditor" path, though:<br /><ol><li><code>UIFieldEditor</code> is a private class in UIKit, so we don't have its headers. Without the headers, <code>@interface MyFieldEditor : UIFieldEditor</code> is going to cause a compiler error, since it won't know how to inherit from <code>UIFieldEditor</code>.</li><li>We don't control the <code>UIFieldEditor</code> instance used by <code>UIKit</code>. Even if we <em>could</em> create our own <code>MyFieldEditor</code>, we still don't know how to swap out the existing shared object for our own.</li></ol>Fortunately, we can handle both of these problems with the same solution: <strong>dynamic subclassing</strong>. We'll create our own subclass of <code>UIFieldEditor</code> <em>at runtime</em> and change the class of the existing field editor to be out new dynamic subclass. This sounds crazy—and it is. But it works<sup id="fnref:kvo"><a href="http://draft.blogger.com/blogger.g?blogID=4974525831038192874#fn:kvo" rel="footnote">1</a></sup>, and it allows us to add our own <code>-deleteBackward</code> functionality without having to swap out existing objects and somehow inform UIKit of what we're doing.<br /><br />Dynamically creating classes at runtime isn't something you're likely to do very often, but it's fairly well documented, and there have been some <a href="http://www.mikeash.com/pyblog/friday-qa-2010-11-6-creating-classes-at-runtime-in-objective-c.html">great</a> <a href="http://funwithobjc.tumblr.com/post/1482787069/dynamic-subclassing">posts</a> about it in the community. I won't bother going into more detail here—it's enough to know that the dynamically-created class works just like any other, once you get it all set up. You just need to allocate a new class pair, register the new class, and add the methods we want to override to the new class. (One caveat of note: calls to <code>objc_allocateClassPair()</code> and <code>objc_registerClass()</code> fail under ARC, so if you're using ARC you'll have to do those in a file that's not using ARC.) You can see how this works in my sample implementation, linked at the end of this post.<br /><br />Once we've created our <code>MyFieldEditor</code> class, though, we still have to actually change the class of the existing <code>UIFieldEditor</code>. This requires using the runtime function <code>object_setClass(id object, Class newClass)</code>. The <code>newClass</code> parameter is easy enough, but what are we going to pass it for the <code>object</code>? We know there's a <code>UIFieldEditor</code> out there, but we still don't have a reference to it.<br /><br />Let's go back to class-dump for a moment. Looking through the method list on <code>UITextField</code>, you'll see a <code>-(id)_fieldEditor</code> method. Sounds like exactly what we want. Unfortunately, we can't just toss that method declaration in a category and then call it directly; that's sure to fail App Store validation for using private API. So we need some way of calling that method without making it <em>look</em> like we're using that method.<br /><br />We could probably do it with <code>-(id)performSelector:</code>, but we clearly can't just create the selector with <code>@selector(_fieldEditor)</code>; that will fail App Store validation just as quickly as calling it directly. We could construct it dynamically from a string, but ARC introduces some caveats when calling <code>-performSelector:</code> with a dynamically-constructed selector because it can't guarantee to get the memory management right. It would be nice to have something that would work correctly without a lot of overhead.<br /><br />Key-Value Coding to the rescue! Key-Value Coding is built around the idea that if you know the name of a property, Cocoa can figure out what the appropriate getters and setters should be. So, rather than trying to figure out the exact method we want to call, let's just ask Cocoa to get the fieldEditor for us:<br /><br /><pre><code>id fieldEditor = [someTextField valueForKey:@"fieldEditor"];</code></pre><br />It's as easy as that.<br /><br /><hr /><h3> Part 4: Making the call</h3><br />At this point, we have a reference to the field editor, and we've created a dynamic <code>UIFieldEditor</code> subclass that we can use to customize its behavior. We never actually added any methods, though; <code>MyFieldEditor</code> doesn't do anything differently from <code>UIFieldEditor</code> yet. We'll need to dynamically add a method to <code>MyFieldEditor</code>, but before we can do that, we need to <em>write</em> the method.<br /><br />Our needs are actually quite simple; when <code>-[MyFieldEditor deleteBackward]</code> is called, we want to call a method letting someone know that a backward deletion happened. Ideally, that "someone" would be the text field itself. Then we want to call through to the superclass implementation. <br /><br />Here's my implementation:<br /><br /><pre><code>- (void)fieldEditor_deleteBackward {<br /><br /> MyTextField *textField = objc_getAssociatedObject(self, BackwardDeleteTargetKey);<br /> [textField my_willDeleteBackward];<br /><br /> // Call through to super<br /> Class superclass = class_getSuperclass([self class]);<br /> SEL deleteBackwardSEL = @selector(deleteBackward);<br /> IMP superIMP = [superclass instanceMethodForSelector:deleteBackwardSEL];<br /> superIMP(self, deleteBackwardSEL);<br />}<br /></code></pre><br />It's really quite simple. We get a reference to the text field using ObjC associated objects, and call <code>-my_willDeleteBackward</code> on it. Then we pass the <code>-deleteBackward</code> method up to the superclass, <code>UIFieldEditor</code>. We have to use the runtime methods to do the superclass call because of the dynamic subclassing game; otherwise, we'd get the wrong superclass.<br /><br />I'm a little nervous about unilaterally changing the behavior of <code>UIFieldEditor</code>, because it seems likely that <em>every text input area in your app</em> uses the same instance of the field editor. So we do a little dance in <code>MyTextField</code>'s implementations of <code>-becomeFirstResponder</code> and <code>-resignFirstResponder</code>. It looks like this:<br /><br /><pre><code>- (BOOL)becomeFirstResponder {<br /> BOOL shouldBecome = [super becomeFirstResponder];<br /> if (shouldBecome == NO) {<br /> return NO;<br /> }<br /><br /> Class myFieldEditorClass = objc_lookUpClass([SubclassName UTF8String]);<br /> if (myFieldEditorClass == nil) {<br /> myFieldEditorClass = registerMyFieldEditor();<br /> }<br /><br /> id fieldEditor = [self valueForKey:@"fieldEditor"];<br /><br /> if (fieldEditor &amp;&amp; myFieldEditorClass) {<br /> object_setClass(fieldEditor, myFieldEditorClass);<br /> objc_setAssociatedObject(fieldEditor, BackwardDeleteTargetKey,<br /> self, OBJC_ASSOCIATION_ASSIGN);<br /> }<br /><br /> return YES;<br />}<br /></code></pre><pre><code><br />- (BOOL)resignFirstResponder {<br /> BOOL shouldResign = [super resignFirstResponder];<br /> if (shouldResign == NO) {<br /> return NO;<br /> }<br /><br /> id fieldEditor = [self valueForKey:@"fieldEditor"];<br /><br /> if (fieldEditor) {<br /> objc_setAssociatedObject(fieldEditor, BackwardDeleteTargetKey,<br /> nil, OBJC_ASSOCIATION_ASSIGN);<br /> Class uiFieldEditorClass = objc_lookUpClass("UIFieldEditor");<br /> if (uiFieldEditorClass) {<br /> object_setClass(fieldEditor, uiFieldEditorClass);<br /> }<br /> }<br /> return YES;<br />}<br /></code></pre><br />With this implementation, the shared <code>UIFieldEditor</code> instance will only be of class <code>MyFieldEditor</code> while the text field is actively the first responder. As soon as the text field resigns, it goes back to being a regular old <code>UIFieldEditor</code>. No other text field in the app will be affected, and this text field will hear about all the backward deletion calls as soon as they come in.<br /><br />This is about the point where everyone working on <code>UIKit</code> starts squirming vigorously. If you'd like people to <em>not</em> do this kind of stuff (which I'd heartily agree with), then let me direct your attention to Radars <a href="rdar://problem/10265826">#10265826</a> and <a href="rdar://problem/10377565">#10377565</a>.<br /><br />In the meantime, use with caution. I haven't tried it in the App Store, but I suspect it will pass validation as there are no symbols referencing any private API in this implementation.<br /><br />The code is <a href="https://github.com/bjhomer/HSBackspaceFriendlyTextField">on GitHub</a>.<br /><div class="footnote"><hr /><ol><li id="fn:kvo">This is actually the same mechanism Cocoa uses to implement Key-Value Observing; when you start observing a property of some object, Cocoa generates a new subclass of that object's class and implements a setter method that wraps your own with calls to <code>-willSetValueForKey:</code> and <code>-didSetValueForKey:</code>. When all observers on an object are gone, its class is set back to the original class. &nbsp;<a href="http://draft.blogger.com/blogger.g?blogID=4974525831038192874#fnref:kvo" rev="footnote" title="Jump back to footnote 1 in the text">↩</a><br /> </li></ol></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-37269826354322306922011-10-14T10:17:00.000-07:002011-10-14T10:17:01.925-07:00Adding a fixed image background to UIWebViewA short post for iOS people.<br /><br /><code>UIWebView</code> doesn't (as of iOS 5.0) honor <code>background-attachment: fixed;</code> in CSS, so if you need a fixed background image on a <code>UIWebView</code>, you're probably searching Google trying to find the answer.<br /><br />Hopefully, this will help.<br /><br /><div style="font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;">UIWebView *someWebView;</div><div style="font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;">someWebView.<span style="color: #7141a3;">opaque</span> = <span style="color: #bc319c;">NO</span>;</div><div style="color: #7141a3; font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;"><span style="color: black;">someWebView.</span>backgroundColor<span style="color: black;"> = [</span>UIColor<span style="color: black;"> </span><span style="color: #3e227c;">clearColor</span><span style="color: black;">];</span></div><div style="color: #7141a3; font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;"><span style="color: black;"><br /></span></div><div style="font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;">UIImageView *imageView;</div><div style="font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;">imageView.<span style="color: #7141a3;">image</span> = [<span style="color: #7141a3;">UIImage</span> <span style="color: #3e227c;">imageNamed</span>:<span style="color: #d32d26;">@"something"</span>];</div><div style="color: #3e227c; font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;"><span style="color: black;">imageView.</span><span style="color: #7141a3;">autoresizingMask</span><span style="color: black;"> = (</span>UIViewAutoresizingFlexibleHeight<span style="color: black;"> |&nbsp;</span>UIViewAutoresizingFlexibleWidth<span style="color: black;">);</span></div><div style="color: #3e227c; font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;"><span style="color: black;">imageView.</span><span style="color: #7141a3;">contentMode</span><span style="color: black;"> = </span>UIViewContentModeScaleToFill<span style="color: black;">;</span></div><div style="font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;">imageView.<span style="color: #7141a3;">frame</span> = someWebView.<span style="color: #7141a3;">bounds</span>;</div><div style="font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;">[someWebView <span style="color: #3e227c;">insertSubview</span>:imageView <span style="color: #3e227c;">atIndex</span>:<span style="color: #2834cf;">0</span>];</div><div style="color: #4d8186; font: 11.0px Menlo; margin: 0.0px 0.0px 0.0px 0.0px;"><code><span class="Apple-style-span" style="font-family: monospace;"></span></code></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-88199964778314171492011-09-29T07:43:00.000-07:002011-09-29T07:43:19.116-07:00@synchronized vs dispatch_onceIn the comments on a <a href="http://stackoverflow.com/questions/4251087/singleton-or-class-methods/4251872#4251872">recent Stack Overflow question</a>, someone asked me if there was a significant performance difference between <code>@synchronized</code> and <code>dispatch_once</code> in implementing a singleton. So I wrote a simple test harness to access a singleton using the <code>@synchronized</code> method shown here: <br /><br /><pre>@synchronized(self) {<br /> if (!synchronizedVar) {<br /> synchronizedVar = [[Test alloc] init];<br /> }<br />}<br />return synchronizedVar;</pre><pre></pre>and the <code>dispatch_once</code> method shown here: <br /><br /><pre>static dispatch_once_t onceToken;<br />dispatch_once(&amp;onceToken, ^{<br /> dispatchVar = [[Test alloc] init];<br />});<br />return dispatchVar;</pre><br />Each test accessed the singleton object 10 million times. I ran both single-threaded tests and multi-threaded tests. Here were the results:<br /><br /><br /><b></b><br /><pre><b>Single threaded results<br />-----------------------<br /> @synchronized: 3.3829 seconds<br /> dispatch_once: 0.9891 seconds<br /><br />Multi threaded results<br />----------------------<br /> @synchronized: 33.5171 seconds<br /> dispatch_once: 1.6648 seconds<br /></b></pre> So yeah, dispatch_once is a lot faster, especially under thread contention. You can find my test harness <a href="https://github.com/bjhomer/Demos">on github</a>. BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-48031194609938596402011-05-27T20:34:00.000-07:002011-05-27T20:44:01.506-07:00Tri-Pic is in the App Store!<a href="http://itunes.com/app/tripic">Tri-Pic</a> is finally in the App Store! I've been working on this as a side project for a few months, and finally got around to finishing it up. It's a fun little app to mix faces and share them via email, Twitter, Facebook, and other services. And it's available now in the App Store, <b style="font-style: italic;">free</b>.<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="http://3.bp.blogspot.com/-gVtufV388eU/TeArkKaFToI/AAAAAAAAAYA/Ou5hq0bqf6I/s1600/Tri-Pic.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://3.bp.blogspot.com/-gVtufV388eU/TeArkKaFToI/AAAAAAAAAYA/Ou5hq0bqf6I/s320/Tri-Pic.png" width="213" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">FrankenMe/my sister/my nephew</td></tr></tbody></table><div class="separator" style="clear: both; text-align: left;"><br /></div>Tri-Pic started out as a project to help my brother with a marketing assignment. In the class they had to come up with a game and do a bunch of market research on it. But it had to be a real game. They were allowed to use an iPhone app only if they knew someone who could actually make that app.<br /><br />As it turns out, my brother knows a guy who can make apps.<br /><br />The arrangement was pretty simple: I'd make the app, they'd use it with for class and get the grade, and then I could do whatever I wanted with it. Awesome. I got the basics done in time for them to finish the course, but it never felt quite ready to put in the App Store.<br /><br />The biggest problem was the initial experience. It's fun to mix faces, of course, but when you first launch the app, it doesn't&nbsp;<i>have</i>&nbsp;any faces. I could have included a bunch of stock faces, but it's at least <i>twice</i> as fun to mix faces of people you know, so I really wanted to avoid stock faces. But the first experience with the app was pretty terrible: you spent at least 2 minutes finding a half-dozen good pictures to use and cropping the face in each one before you ever got to mix any faces. Two minutes of tedium isn't a great introduction to <i>any</i>&nbsp;app.<br /><br />So I added face detection using <a href="http://opencv.willowgarage.com/wiki/">OpenCV</a>. Tri-Pic will scan your photo library and look for faces, automatically adding them to the database.&nbsp;And even better is that on devices that support multitasking, this detection can continue in the background while off browsing the web or tweeting about Tri-Pic. The initial experience went from super lame to magical.<br /><br />Is Tri-Pic going to earn an Apple Design Award? Not likely. Nor is it going to change the world, or fix the economy, or anything else monumental. But it's fun, it's free, and you'll at least get a smile or two out of it.&nbsp;And really, who can't use a smile?<br /><br /><a href="http://itunes.com/app/tripic">Download Tri-Pic</a>.<br /><br /><span class="Apple-style-span" style="font-size: x-small;">P.S. If you download it before the next update is approved, you may catch a reference to a previous working name. Let's just call it an easter egg, and not a really lame error, okay?</span>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-83600000464565895612011-04-14T21:14:00.000-07:002013-02-22T10:45:58.538-08:00Subclassing NSInputStreamCocoa's NSInputStream is great, but sometimes it doesn't have all the functionality you need. For example, you might want to dynamically encrypt the file as you were streaming it off the disk, or you might want to put up a progress bar indicating how far the input stream had progressed through a large file. NSInputStream doesn't support either of these options natively, but this sounds like a great place for an NSInputStream subclass, right?<br /><br />Wrong.<br /><br />Or rather, right, with the caveat that subclasses of NSInputStream don't work correctly when used with Cocoa's URL loading mechanism. ( folks: See <a href="rdar://problem/3222783">rdar://problem/3222783</a>.)<br /><br /><h3>The Problem</h3><br />When you make an NSInputStream subclass and try to pass it to -[NSURLRequest setHTTPBodyStream:], your app will quickly crash with an 'unrecognized selector' for the following method:<br /><br /><pre><code>- (void) _scheduleInCFRunLoop: (CFRunLoopRef) inRunLoop forMode: (CFStringRef) inMode</code></pre><br /><br />If you implement that, you'll then get another unrecognized selector:<br /><br /><pre><code>- (BOOL) _setCFClientFlags: (CFOptionFlags)inFlags<br /> callback: (CFReadStreamClientCallBack) inCallback<br /> context: (CFStreamClientContext *) inContext</code></pre><br />If you give that one an empty implementation too (<code>return YES;</code>) and the file you're uploading is small, you may manage to make it to a third unimplemented selector:<br /><br /><pre><code>- (void) _unscheduleFromCFRunLoop:(CFRunLoopRef)inRunLoop forMode:(CFStringRef)inMode</code></pre><br /><br />Unfortunately, while you can avoid the unrecognized selector crashes by implementing these methods, you're very unlikely to get through your whole stream. Further, <a href="http://lists.apple.com/archives/macnetworkprog/2007/May/msg00056.html">Apple engineers have stated</a> that such naive implementations are "definitely not safe" and will likely lead to failing in "strange and unexpected ways."<br /><br /><h3>The backstory</h3><br />The real question here is what these methods are for in the first place. It turns out that these three methods are simply the toll-free bridging versions of <code>CFReadStreamScheduleWithRunLoop</code>, <code>CFReadStreamSetClient</code>, and <code>CFReadStreamUnscheduleFromRunLoop</code>, respectively. Calling <code>CFReadStreamScheduleWithRunLoop</code> from <code>_scheduleInCFRunLoop:...</code>, for example, is a quick way to infinite recursion.<br /><br />The <code>NSStream</code> documentation indicates that subclasses must override <code>-(void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode</code> and <code>-(void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode</code>. Why? Because the stream's delegate usually needs to be notified when there are bytes available to be read, and that getting that information often requires being scheduled on a run loop. <i>Our three mystery methods serve the same purpose.</i><br /><br /><code>NSInputStream</code> is toll-free bridged with <code>CFReadStream</code>. Mostly. From the <code>CFReadStream</code> Reference:<br /><blockquote>CFReadStream is “toll-free bridged” with its Cocoa Foundation counterpart, NSInputStream. This means that the Core Foundation type is interchangeable in function or method calls with the bridged Foundation object. Therefore, in a method where you see an NSInputStream * parameter, you can pass in a CFReadStreamRef, and in a function where you see a CFReadStreamRef parameter, you can pass in an NSInputStream instance. <i>Note, however, that you may have either a delegate or callbacks but not both.</i> </blockquote>These methods are required to support the CFReadStream client callbacks, which are distinct from the delegate callbacks.<br /><br /><h3>The solution</h3><br /><code>-[NSInputStream _scheduleInCFRunLoop:forMode:]</code> is the equivalent of <a href="http://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFReadStreamRef/Reference/reference.html#//apple_ref/doc/uid/20001440-CH1g-F17791"><code>CFReadStreamScheduleWithRunLoop</code></a> for your stream. Do whatever you need to do so that you can give proper <code>kCFStreamEventHasBytesAvailable</code> notifications (and any other notifications requested) at the proper time. That may involve scheduling a timer on the run loop, or if your subclass is just wrapping a vanilla NSInputStream, simply scheduling <i>that</i> stream on the run loop. Implement this method as if you were implementing <a href="http://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFReadStreamRef/Reference/reference.html#//apple_ref/doc/uid/20001440-CH1g-F17791"><code>CFReadStreamScheduleWithRunLoop</code></a> for your stream<br /><br /><code>-[NSInputStream _setCFClientFlags:callback:context:]</code> is the equivalent of <a href="http://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFReadStreamRef/Reference/reference.html#//apple_ref/doc/uid/20001440-CH1g-F17789"><code>CFReadStreamSetClient</code></a>, you need to do a few things. If the <code>context</code> and <code>callback</code> arguments are not <code>NULL</code>, the caller is trying to set up a callback client.<br /><ol><li>Inspect the flags, and record which notifications are requested. The possible values are listed in the <a href="http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFStreamConstants/Reference/reference.html#//apple_ref/c/tdef/CFStreamEventType">CFStream Event Type Constants documentation</a>.</li><li>Copy the pointer to the callback function. You'll need to use it later.</li><li>Copy the context. The documentation for <code>CFReadStreamSetClient</code> indicates that the context struct passed by the caller should be copied, and that the caller is not responsible for preserving it. <code>memcpy(&amp;myLocalContextCopy, thePassedContext, sizeof( CFStreamClientContext))</code> works just fine.</li><li>Retain the context-&gt;info. The context struct includes a <code>void *info</code> member and a <code>CFAllocatorRetainCallBack retain</code> member. Call the retain function on the info pointer (if the retain function is not nil).</li></ol>If the <code>context</code> and <code>callback</code> parameters <i>are</i> <code>NULL</code>, then the caller is removing the callback client, and you need to do the following: <br /><ol><li>Call the <code>release</code> function (from the context you previously copied) on the <code>info</code> pointer in that context.</li><li>Remove your copy of the context and callback; they are no longer needed.</li></ol>Finally, return <code>YES</code> to indicate that the asynchronous scheduling was successful.<br /><br /><code>-[NSInputStream _unscheduleFromCFRunLoop:forMode]</code> is the equivalent of <a href="http://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFReadStreamRef/Reference/reference.html#//apple_ref/doc/uid/20001440-CH1g-F17793"><code>CFReadStreamUnscheduleFromRunLoop</code></a>. You should remove anything you scheduled in the <code>_scheduleInCFRunLoop:forMode:</code> method.<br /><br />Once you've done these, make sure you've implemented the other methods required for subclasses as documented in the NSInputStream and NSStream reference. Now, when you pass off your NSInputStream subclass to NSURLRequest, your stream will be scheduled on the run loop and the client callbacks will be set up. Once you're scheduled on the run loop, you should be able to notify your client when you have bytes available to read, when you've reached the end of the file, and when an error has occurred. Make sure you're passing those along correctly, and everything will be good to go.<br /><br /><h3>Sample</h3><br />I've put together a sample implementation of an NSInputStream subclass that demonstrates what I've presented. <a href="https://github.com/bjhomer/HSCountingInputStream">HSCountingInputStream</a> is a simple class that wraps an NSInputStream, counting the number of instances of a given character have passed through it. Nearly every call is simply passed through to the underlying NSInputStream; the only real code of interest is in the <code>-read:maxLength:</code> and in the undocumented methods discussed above.<br /><br />I'll keep an eye on the comments, so if you have any questions, please let me know. I'll probably write up another blog here shortly about how I figured all of this out, for those who are interested.BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-3549329229479578382009-08-28T12:22:00.000-07:002010-07-11T06:54:20.883-07:00Creating a Finder alias programmatically on Snow LeopardMy co-worker Dan posted a blog yesterday entitled "<a href="http://www.danandcheryl.com/2009/08/how-to-create-an-alias-programmatically">How to Create an Alias Programmatically</a>". His example is 21 lines long, and is compatible with Leopard and earlier. It only works if the original item is a folder (though creating an alias to a file is not much different). The code messes with resource forks, and the C interface is generally difficult to read for someone who spends most of their time in Objective-C. The code is also not guaranteed to be 100% accurate, since Apple explicitly did not support programmatic alias creation in Leopard.<div><br /></div><div>This is a great example of how Apple has improved the developer experience for OS X in Snow Leopard. Snow Leopard contains some new APIs for "bookmark" creation, which appears to be the new behind-the-scenes name for aliases. The following four lines of code create a functioning alias on Snow Leopard:</div><div><br /></div><div><pre>NSURL *src = [NSURL URLWithString:@"file:///Users/bjh/Desktop/temp.m"];<br />NSURL *dest = [NSURL URLWithString:@"file:///Users/bjh/Desktop/myalias"];<br /><br />NSData *bookmarkData = [src bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile<br />includingResourceValuesForKeys:nil<br />relativeToURL:nil<br />error:NULL];<br />[NSURL writeBookmarkData:bookmarkData<br />toURL:dest<br />options:0<br />error:NULL];</pre><br /></div><div>Isn't that about a billion times easier?</div><div><br /></div><div>I'm not sure what the relativeToURL: parameter is for yet; comments are welcome.<br /></div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-69636706664747621192009-07-09T18:07:00.000-07:002009-07-09T18:12:39.429-07:00100 Hour Board iPhone app v1.2 releasedAs of this previous Sunday, 100 Hour Board for iPhone was updated to version 1.2. This update includes support for iPhone OS 3.0, improves the rendering of quotes in Board posts, and teaches the app to remember where you were when you last closed it. There are also a couple minor user interface tweaks; notably, when posts download they should appear in the list with a smooth animation.<div><br /></div><div>Go check it out! <a href="http://tinyurl.com/100hourapp">http://tinyurl.com/100hourapp</a> (iTunes Music Store link)</div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-32109180218587446982009-06-16T21:52:00.000-07:002010-03-30T21:18:28.349-07:00Singleton Pattern in CocoaPeter Hosey recently <a href="https://twitter.com/boredzo/status/2201415345">tweeted</a>:<blockquote>From the “how NOT to implement a Cocoa singleton” dept: <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32">http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32</a></blockquote><br /><a href="https://twitter.com/boredzo/status/2201642358">followed by</a>:<br /><blockquote>If something over-releases an object, the bug is not in that object, and overriding methods in it to break retain/release is not fixing it.</blockquote><br />The code sample in question is in the Apple documentation, and prescribes overriding the following methods for a singleton object: <code>allocWithZone</code>:, <code>copyWithZone:</code>, <code>retain</code>, <code>release</code>, <code>autorelease</code>, and <code>retainCount</code>. In addition, it also recommends implementing a <code>sharedFloozit</code> class method, so that users of your class are aware they're using a singleton. Go read that section, or you'll be lost for the rest of this post.<br /><br />Really, I mean it. Go read that documentation. I'll be referring to it a lot.<br /><br />That's a lot of methods to override just to implement a singleton. More to the point, a lot of it seems unnecessary. After all, as long as everyone else is doing their memory management correctly, retain counts shouldn't matter, right?<br /><br />Wrong.<br /><br />First, though, we need to get a definition straight. A singleton is a class of which there should only be <span style="font-weight:bold;">one</span> instance in any given process. There are actually very few singleton classes in the Cocoa framework including <code>NSDocumentController</code> and <code>NSFontManager</code>. [1] You cannot create more than one of these objects; if you try to call<code> [[NSDocumentController alloc] init]</code>, you'll get back the exact same object as you do when you call <code>[NSDocument sharedDocumentController]</code>, no matter how many times you call alloc and init. <code>NSApplication</code> is arguably a singleton as well; you can alloc another one, but you'll get an assertion failure when you call init.<br /><br />Singletons are generally useful when initializing an object takes an inordinate amount of time. <code>NSFontManager</code>, for example, has to search several locations on the filesystem in order to do its job. You really don't want to be constantly initializing an <code>NSFontManager</code>. Further, it makes very little sense to have more than one instance of <code>NSApplication</code> within your application. Having one shared object for the whole system can simplify and optimize certain things. [2]<br /><br />So that's a singleton. Only one instance allowed in the entire process.<br /><br />There are other classes that have a <code>+[SomethingClass sharedSomething]</code> method or a <code>+[SomethingClass defaultSomething]</code> method. These methods provide access to an instance of the object intended to be shared by all users of the class, but do not prohibit the creation of another instance. Indeed, the <a href="http://developer.apple.com/releasenotes/Cocoa/Foundation.html#NSFileManager">Leopard Developer Release Notes</a> specifically note that creating multiple instances of <code>NSFileManager</code> is possible and thread-safe, despite the existence of a globally-available object through <code>+[NSFileManager defaultManager]</code>. <span style="font-weight:bold;">These are not singletons</span>. If you're writing a class which provides a shared instance but doesn't not prohibit creation of other instances, then you should absolutely not override <code>retain</code>, <code>release</code>, <code>autorelease</code>, and <code>retainCount</code>, and should probably not override <code>allocWithZone:</code> either.<br /><br />Most of the time, you don't need a singleton. Just the mention of a singleton is enough to get some people up in arms. But if you <span style="font-weight:bold;">really truly</span> need a singleton, then there's good reason for overriding the methods listed above.<br /><br />Consider the following example:<br /><code><br />MyFloozit *floozit1 = [[MyFloozit alloc] init];<br />[floozit1 doSomething];<br />[floozit1 release];<br /><br />MyFloozit *floozit2 = [[MyFloozit alloc] init]; // MyFloozit is a singleton, so this should be the same object as floozit1<br />[floozit2 doSomething]; // CRASH HERE<br />[floozit2 release];<br /></code><br /><br />When <code>floozit1</code> is set, a new <code>MyFloozit</code> is allocated, and a static <code>MyFloozit</code> pointer is set. When <code>floozit1</code> is released, that static pointer <span style="font-style:italic;">is still pointing to the old instance</span>. As a result, when we try to set <code>floozit2</code> (or when anyone else tries to call <code>[MyFloozit sharedFloozit]</code>), we get back a pointer to that same instance. <span style="font-style:italic;">The one that has been dealloc-ed</span>. Right there, despite following all the standard rules of memory management, you've crashed. The example might seem contrived, but if <code>floozit1</code> and <code>floozit2</code> are in separate methods (or separate threads calling the same method), this could be a very common scenario.<br /><br />The point is, if you override <code>allocWithZone:</code> to force a class to be a singleton, then you <span style="font-style:italic;">must</span> override <code>release</code> (and <code>autorelease</code>), or else anyone who believes they have ownership (after to calling <code>init</code>) will crash your program. Once you're disabling retain counting by overriding <code>release</code>, you might as well override <code>retain</code> and <code>retainCount</code> as well, to be consistent.<br /><br />In the Apple Documentation linked above, there is a short paragraph right after the code showing the recommended way to override the various methods. It says:<br /><blockquote>Situations could arise where you want a singleton instance (created and controlled by the class factory method) but also have the ability to create other instances as needed through allocation and initialization. In these cases, you would not override <code>allocWithZone:</code> and the other methods following it as shown in Listing 2-15.</blockquote>In this situation, I agree with Peter (and Apple) completely; don't override the memory management methods. I disagree with calling it a singleton, but whatever you want to call it, it's clear that you need those memory management methods.<br /><br />If you think you need a singleton, think again. If you still think you need a singleton, bounce it off someone else to disabuse you of the notion. If you <span style="font-style:italic;">still</span> need a singleton, then follow Apple's advice and override the memory management methods. Otherwise, you'll crash.<br /><br />Of course, if you're using garbage collection, all retain count operations are no-ops, so none of this matters anyway. Feel free to go on your merry way, pitying the poor souls still living in a retain-counted world.<br /><br />[1] The documentation referenced by Peter on "Creating a Singleton Instance" lists <code>NSFileManager</code> and <code>NSWorkspace</code> as examples of singletons, but this is incorrect. It is possible to create more than one instance of both these classes; Cocoa just happens to provide easy access to a shared instance which they suggest you use.<br /><br />[2] It can also complicate a lot of things by introducing shared state. I'm not arguing for the use of the singleton pattern; I <a href="https://twitter.com/boredzo/status/2201754228">agree with Peter</a> that most of the time, if you're using a singleton then you're "Doin It Rong". I'm simply arguing for Apple's implementation of the singleton pattern in the case where you really <i>do</i> need a singleton.BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-50079328422414995142009-03-31T11:05:00.000-07:002009-03-31T11:10:55.918-07:00100 Hour Board released... a week agoOn March 19, my 100 Hour Board app was officially available in the App Store. There were nearly 100 downloads in the first two days, and that was before I'd even started doing any advertising.<div><br /></div><div>Anyway, if you haven't downloaded it yet, it's available <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=307845884&amp;mt=8">in the App Store here</a>. (Link opens in iTunes.)</div><div><br /></div><div>I've got a small update waiting for approval right now. It adds a popup alert when a search returns no results, so that users don't think it's just a slow search. Next on the feature list is read/unread tracking for daily posts.</div>BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-26586063888671330992009-03-09T09:43:00.000-07:002009-03-09T10:44:56.686-07:00100 Hour Board iPhone app coming soonI'm a big fan of BYU's <a href="http://theboard.byu.edu">100 Hour Board</a>, an online Q&A forum that provides answers to nearly any question imaginable within 100 hours. I've been working with their webmasters over the last few weeks to get a web API to their content, and today I'm uploading an app that provides an iPhone-optimized interface to the 100 Hour Board. It's a fantastic interface on an awesome website, and I'm excited for it to go live.<br /><br />I'll be sure to post as it's available.BJ Homernoreply@blogger.comtag:blogger.com,1999:blog-4974525831038192874.post-60164088393133827602009-02-11T17:00:00.000-08:002009-03-09T09:41:44.032-07:00Surakarta is now availableSurakarta for the iPhone/iPod Touch is <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=304075492&amp;mt=8">now available for download</a>. (Link opens in iTunes.) I haven't yet been able to find it directly by searching, but hopefully the App Store index will update shortly.<div><br /></div><div>I'm currently working on version 1.1, where I'll add single-player support. In the meantime, download Surakarta and write a review!</div><div><br /></div><div><b>UPDATE </b>(6:04 pm)<b>: </b>Sometime in the last 10 minutes, it showed up through search. Hooray!</div>BJ Homernoreply@blogger.com