diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2517e572..f8b3884b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,6 @@ jobs: run: bundle exec jekyll build - name: danger - env: + env: DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} run: bundle exec danger diff --git a/.github/workflows/markdown-checker.yml b/.github/workflows/markdown-checker.yml new file mode 100644 index 00000000..beb61552 --- /dev/null +++ b/.github/workflows/markdown-checker.yml @@ -0,0 +1,29 @@ +name: Markdown Checker + +on: + push: + branches: + - master + pull_request: + branches: + - master + schedule: + # Run on first day of every month + # See: + # - https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onschedule + - cron: '0 0 1 * *' + +jobs: + job-1: + name: Link Check + runs-on: ubuntu-latest + steps: + - name: git checkout + uses: actions/checkout@v1 + + # https://github.com/marketplace/actions/markdown-link-check + - name: markdown-link-check + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' + config-file: '.github/workflows/markdown-link-check-config.json' diff --git a/.github/workflows/markdown-link-check-config.json b/.github/workflows/markdown-link-check-config.json new file mode 100644 index 00000000..c2e0f716 --- /dev/null +++ b/.github/workflows/markdown-link-check-config.json @@ -0,0 +1,14 @@ +{ + // Regex: https://regexr.com + "ignorePatterns": [ + { + // ignore relative links, example: '/contact' + "pattern": "/\/[^\/][\w\d]*/g" + } + ], + + "retryOn429": false, + + // ignore 0 and 429 + "aliveStatusCodes":[200, 206, 0, 429] +} diff --git a/README.md b/README.md index c72672f1..14d3aa6e 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,13 @@ ![Logo](https://www.jessesquires.com/ico/favicon-180-precomposed.png) +[Broken link](www.jessesquires.com/asdfasdfasdfasdf) + ## About This is my personal site and blog. -Built with [Jekyll](https://jekyllrb.com), [Bootstrap](https://getbootstrap.com), [jQuery](https://jquery.com), and [Font Awesome](https://fontawesome.com). Hosted at [NearlyFreeSpeech](https://nearlyfreespeech.net/). +Built with [Jekyll](https://jekyllrb.com), [Bootstrap](https://getbootstrap.com), [jQuery](https://jquery.com), and [Font Awesome](https://fontawesome.com). Hosted at [NearlyFreeSpeech](https://nearlyfreespeech.net). ## Requirements diff --git a/_posts/2014-06-25-apples-to-apples.md b/_posts/2014-06-25-apples-to-apples.md index 1bcb65ec..cb5ab778 100644 --- a/_posts/2014-06-25-apples-to-apples.md +++ b/_posts/2014-06-25-apples-to-apples.md @@ -52,7 +52,7 @@ These two programs were carefully crafted to be a true *apples-to-apples* compar The following were used for the standard library sorts: -{% highlight swift %} +```swift // Swift var arr: [Int] = // some array @@ -64,7 +64,7 @@ NSMutableArray *arr = // some array return [n1 compare:n2]; }]; -{% endhighlight %} +``` Previous Swift std lib sort implementation here. diff --git a/_posts/2014-08-06-apples-to-apples-part-two.md b/_posts/2014-08-06-apples-to-apples-part-two.md index 994acbff..8b8b689d 100644 --- a/_posts/2014-08-06-apples-to-apples-part-two.md +++ b/_posts/2014-08-06-apples-to-apples-part-two.md @@ -13,7 +13,7 @@ If at first you don't succeed, try, try again. Practice makes perfect. These pro This week, Apple has reminded us of the value of this iterative process and its rewards with the fifth beta release of Xcode 6, iOS 8, OS X Yosemite, and most importantly — *Swift*. This update includes a [number of improvements](http://adcdownload.apple.com//Developer_Tools/xcode_6_beta_5_za4gu6/xcode_6_beta_5_release_notes.pdf), but perhaps the most interesting are those not listed. Swift was rough around the edges during its launch at [WWDC](https://developer.apple.com/wwdc/), but it is **definitely** beginning to live up to its name. -If you missed my first post, [*Apples to Apples*](/apples-to-apples/), you should head over there now to catch up. +If you missed my first post, [*Apples to Apples*]({{ site.url }}{% post_url 2014-06-25-apples-to-apples %}), you should head over there now to catch up. ### Setup diff --git a/_posts/2014-08-19-on-the-value-of-benchmarks.md b/_posts/2014-08-19-on-the-value-of-benchmarks.md index 6703b2e4..e46d71fa 100644 --- a/_posts/2014-08-19-on-the-value-of-benchmarks.md +++ b/_posts/2014-08-19-on-the-value-of-benchmarks.md @@ -7,7 +7,7 @@ title: On the value of benchmarks subtitle: A brief examination of measuring code performance --- -As [*Apples to apples, Part II*](/apples-to-apples-part-two/) made its way around the web, it was [praised](https://twitter.com/SwiftLang/status/497057489766981632) as well as [critiqued](https://twitter.com/benpickering/status/497127012814041088). The latter largely consisted of questions regarding the real-world applications of these benchmarks. In general, benchmarks should be taken with a grain of salt. I want to take a minute to clarify my thoughts on benchmarks and how I think they can be valuable. +As [*Apples to apples, Part II*]({{ site.url }}{% post_url 2014-08-06-apples-to-apples-part-two %}) made its way around the web, it was [praised](https://twitter.com/SwiftLang/status/497057489766981632) as well as [critiqued](https://twitter.com/benpickering/status/497127012814041088). The latter largely consisted of questions regarding the real-world applications of these benchmarks. In general, benchmarks should be taken with a grain of salt. I want to take a minute to clarify my thoughts on benchmarks and how I think they can be valuable. diff --git a/_posts/2014-08-21-apples-to-apples-part-three.md b/_posts/2014-08-21-apples-to-apples-part-three.md index 2687dcf7..82d1d6b4 100644 --- a/_posts/2014-08-21-apples-to-apples-part-three.md +++ b/_posts/2014-08-21-apples-to-apples-part-three.md @@ -11,7 +11,7 @@ subtitle: A modest proposal: can Swift outperform plain C? -In [*Apples to apples, Part II*](/apples-to-apples-part-two/), we discovered that Swift was finally performing better than Objective-C. As expected, some common [reactions](https://twitter.com/OldManKris/status/497102303833255936) and [responses](https://twitter.com/mpweiher/status/497066155224608768) on Twitter were, *then how does it compare to C?* This is precisely what we are investigating today to welcome this week's arrival of [Xcode 6 beta 6](https://developer.apple.com/xcode/downloads/). +In [*Apples to apples, Part II*]({{ site.url }}{% post_url 2014-08-06-apples-to-apples-part-two %}), we discovered that Swift was finally performing better than Objective-C. As expected, some common [reactions](https://twitter.com/OldManKris/status/497102303833255936) and [responses](https://twitter.com/mpweiher/status/497066155224608768) on Twitter were, *then how does it compare to C?* This is precisely what we are investigating today to welcome this week's arrival of [Xcode 6 beta 6](https://developer.apple.com/xcode/downloads/). ### Setup @@ -19,7 +19,7 @@ In [*Apples to apples, Part II*](/apples-to-apples-part-two/), we discovered tha * *Software:* OS X Mavericks 10.9.4, Xcode 6 beta 6 * *Hardware:* 2008 unibody MacBook Pro, 2.4 Ghz Intel Core 2 Duo, 8 GB 1067 MHz DDR3 memory -

The benchmarks consist of T trials, which are averaged at the end to obtain the average execution time for each algorithm. Each trial begins by generating an array of N random integers in the range [0, UINT32_MAX). Then, each sorting algorithm is passed a copy of this initial array to sort. The current time is logged before and after each sort and the difference between the two yields the execution time for the algorithm for the current trial. Each execution time is saved to find the average time and standard deviation after all trials are complete.

+The benchmarks consist of T trials, which are averaged at the end to obtain the average execution time for each algorithm. Each trial begins by generating an array of N random integers in the range [0, UINT32_MAX). Then, each sorting algorithm is passed a copy of this initial array to sort. The current time is logged before and after each sort and the difference between the two yields the execution time for the algorithm for the current trial. Each execution time is saved to find the average time and standard deviation after all trials are complete. The sorting algorithms are written as [textbook implementations](http://en.wikipedia.org/wiki/Introduction_to_Algorithms) for clarity, objectivity, and fairness to each language. The standard library sort for Swift uses the `sorted()` [function](https://gist.github.com/jessesquires/06b6bd68a7d18810651f#file-sorts-m) while C uses `qsort()` from [cstdlib](http://www.cplusplus.com/reference/cstdlib/qsort/). diff --git a/_posts/2014-10-22-swift-failable-initializers.md b/_posts/2014-10-22-swift-failable-initializers.md index 31142a6b..0f400433 100644 --- a/_posts/2014-10-22-swift-failable-initializers.md +++ b/_posts/2014-10-22-swift-failable-initializers.md @@ -32,7 +32,7 @@ Apple's [article](https://developer.apple.com/swift/blog/?id=17) provides an exa However, failable initializers might seduce you into doing something bad. Suppose we have a blog post object. It requires the body text, the date it was written, and an image. To "simplify" construction of a post, you decide to pass the name of an image, instead of a `UIImage` object. -{% highlight swift %} +```swift class MyPost { @@ -53,13 +53,13 @@ class MyPost { } } -{% endhighlight %} +``` If the image cannot be constructed, then the initialization of `MyPost` fails. What have we done by designing our `init?` this way? We have disregarded the [SOLID](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) principles, specifically [single responsibility](http://en.wikipedia.org/wiki/Single_responsibility_principle) and [dependency inversion](http://en.wikipedia.org/wiki/Dependency_inversion_principle). The `MyPost` object is for storing blog post data. It should not be initializing an image. The dependency on `UIImage` is now obfuscated. And finally, we have to do our optional unwrapping dance every time we instantiate a post. We can fix these issues by passing a non-optional image to our initializer. -{% highlight swift %} +```swift class MyBetterPost { @@ -74,7 +74,7 @@ class MyBetterPost { } } -{% endhighlight %} +``` Clean and deterministic again. But you're probably thinking, *we still have to handle an optional image __somewhere__*. That's true. When constructing a `UIImage`, the initializer `init(named name: String) -> UIImage?` could return `nil`, but the point is that this should be happening *outside* of this class, and definitely **not** in `init`. There's no good reason to dirty up this class with optionals. diff --git a/_posts/2014-12-05-rosetta-stone-contributes.md b/_posts/2014-12-05-rosetta-stone-contributes.md index c622f75a..c82eb7fa 100644 --- a/_posts/2014-12-05-rosetta-stone-contributes.md +++ b/_posts/2014-12-05-rosetta-stone-contributes.md @@ -13,6 +13,6 @@ I'm incredibly happy and incredibly proud to share that [Rosetta Stone](http://w See [my post](http://product.rosettastone.com/rosetta-stone-is-now-on-github/) on our product/engineering [blog](http://product.rosettastone.com/news/) for the official announcement. I think the [value](http://tom.preston-werner.com/2011/11/22/open-source-everything.html) and [benefits](http://ashfurrow.com/blog/sharing-is-selfish/) of open-source are clear, and immeasurable. Every great engineer that I know agrees. So I couldn't be more excited about this news. -And to top it off, I helped author our *first* **ever** open-source project! Today we released an initial version of [RSTCoreDataKit](https://github.com/rosettastone/RSTCoreDataKit), an iOS library for making [Core Data](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html) easier to use. This is just a start and there's certainly more coming. This is only the beginning. +And to top it off, I helped author our *first* **ever** open-source project! Today we released an initial version of [RSTCoreDataKit](https://github.com/rosettastone/RSTCoreDataKit), an iOS library for making [Core Data](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/) easier to use. This is just a start and there's certainly more coming. This is only the beginning. Now go show us some love on [GitHub](https://github.com/rosettastone). diff --git a/_posts/2014-12-08-introducing-jsqmessagesvc-6-0.md b/_posts/2014-12-08-introducing-jsqmessagesvc-6-0.md index 1de46dca..d6881198 100644 --- a/_posts/2014-12-08-introducing-jsqmessagesvc-6-0.md +++ b/_posts/2014-12-08-introducing-jsqmessagesvc-6-0.md @@ -21,7 +21,7 @@ A few weeks ago I published the [sixth major release](https://github.com/jessesq ### A brief history -It all began with [Hemoglobe](http://bit.ly/hemoglobeapp), an app for the bleeding disorder community. I built this app with [Michael Schultz](http://michaelschultz.com) almost two years ago, and one of the main features was... *private user messages*. I searched on [GitHub](https://github.com) and [CocoaControls](https://www.cocoacontrols.com) for an existing open-source framework. What I found was a lot of [great attempts](https://www.cocoacontrols.com/search?utf8=āœ“&q=messages) and partially completed projects. However, one [abandoned project](https://github.com/samsoffes/ssmessagesviewcontroller) stuck out and gave me some great ideas to get started. +It all began with [Hemoglobe](https://hemoglobe.com), an app for the bleeding disorder community. I built this app with [Michael Schultz](http://michaelschultz.com) almost two years ago, and one of the main features was... *private user messages*. I searched on [GitHub](https://github.com) and [CocoaControls](https://www.cocoacontrols.com) for an existing open-source framework. What I found was a lot of [great attempts](https://www.cocoacontrols.com/search?q=messages) and partially completed projects. However, one [abandoned project](https://github.com/samsoffes/ssmessagesviewcontroller) stuck out and gave me some great ideas to get started. [CocoaPods](http://cocoapods.org) was just entering its third year back then and was not very mainstream. I knew very little about it until [an issue](https://github.com/jessesquires/JSQMessagesViewController/issues/3) was opened that requested CocoaPod support and I received my [first pull-request](https://github.com/jessesquires/JSQMessagesViewController/pull/4) to add a [podspec](http://guides.cocoapods.org/syntax/podspec.html). @@ -52,7 +52,7 @@ One of the most challenging aspects of developing a framework is making assumpti -So how do we implement *the model* in *Model-View-Controller* when we have no idea what the model will be? *Every* developer that wants to use this library will have a *unique* model. Class names will be different, variable names will be different, the persistence layer ([Core Data](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html) or otherwise) will be different. We unify these differences with [Protocols](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html) (or [Interfaces](http://en.wikipedia.org/wiki/Interface_(Java))). This is the [L](http://en.wikipedia.org/wiki/Liskov_substitution_principle) in [SOLID](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)), and it is one of the most powerful design tools that you have. +So how do we implement *the model* in *Model-View-Controller* when we have no idea what the model will be? *Every* developer that wants to use this library will have a *unique* model. Class names will be different, variable names will be different, the persistence layer ([Core Data](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/) or otherwise) will be different. We unify these differences with [Protocols](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html) (or [Interfaces](http://en.wikipedia.org/wiki/Interface_(Java))). This is the [L](http://en.wikipedia.org/wiki/Liskov_substitution_principle) in [SOLID](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)), and it is one of the most powerful design tools that you have. There are 4 data protocols for the model layer: diff --git a/_posts/2015-01-05-swift-coredata-and-testing.md b/_posts/2015-01-05-swift-coredata-and-testing.md index 88fbd14f..2bb103a5 100644 --- a/_posts/2015-01-05-swift-coredata-and-testing.md +++ b/_posts/2015-01-05-swift-coredata-and-testing.md @@ -13,7 +13,7 @@ image: half_width: false --- -[Core Data](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html) is probably loved as much as it is shunned by iOS developers. It is a framework of great power that often comes with great frustration. But it remains a popular tool among developers despite its pitfalls — likely because Apple continues to [invest](https://developer.apple.com/videos/wwdc/2014/?id=225) in it and encourages its adoption, as well as the availability of the [many](http://nshipster.com/core-data-libraries-and-utilities/) open-source [libraries](https://github.com/rosettastone/RSTCoreDataKit) that make Core Data easier to use. Consider unit testing, and Core Data gets a bit more cumbersome. Luckily, there are [established techniques](https://github.com/rosettastone/RSTCoreDataKit#unit-testing) to facilitate testing your models. Add [Swift](http://www.apple.com/swift/) to this equation, and the learning curve gets slightly steeper. +[Core Data](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/) is probably loved as much as it is shunned by iOS developers. It is a framework of great power that often comes with great frustration. But it remains a popular tool among developers despite its pitfalls — likely because Apple continues to [invest](https://developer.apple.com/videos/wwdc/2014/?id=225) in it and encourages its adoption, as well as the availability of the [many](http://nshipster.com/core-data-libraries-and-utilities/) open-source [libraries](https://github.com/rosettastone/RSTCoreDataKit) that make Core Data easier to use. Consider unit testing, and Core Data gets a bit more cumbersome. Luckily, there are [established techniques](https://github.com/rosettastone/RSTCoreDataKit#unit-testing) to facilitate testing your models. Add [Swift](http://www.apple.com/swift/) to this equation, and the learning curve gets slightly steeper. @@ -36,7 +36,7 @@ Not very helpful, is it? When I first saw this, it took me a few puzzling minute Most of the existing Objective-C Core Data libraries that you'll find implement the following helper methods in some way, if not verbatim. These methods mitigate the awkwardness of inserting new objects into Core Data and avoid [*stringly-typed* Objective-C](http://corner.squareup.com/2014/02/objc-codegenutils.html). -{% highlight swift %} +```swift @implementation NSManagedObject (Helpers) @@ -53,11 +53,11 @@ Most of the existing Objective-C Core Data libraries that you'll find implement @end -{% endhighlight %} +``` I have decided to use Swift for one of my side projects, and in designing the model layer of the app my first thought was to rewrite these methods in Swift. Let's see what that would look like. -{% highlight swift %} +```swift extension NSManagedObject { @@ -73,13 +73,13 @@ extension NSManagedObject { } -{% endhighlight %} +``` Hm. The `entityName()` function just became much less elegant. Remember, we have to prefix our Swift classes for Core Data which means their fully qualified names take the form `.`. This means we must parse out the *entity name* which is the class name only. This seems fragile and probably isn't a good idea. Additionally, we have to use the `object_getClass()` function from the [Objective-C runtime library](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html), which feels dirty — *even in Objective-C*. I've always avoided using such [runtime](http://nshipster.com/associated-objects/) [voodoo](http://nshipster.com/method-swizzling/) as much as possible, opting for actual design patterns instead. Even `NSStringFromClass()` feels *wrong* in Swift. And generally speaking, *what do we gain by simply rewriting our __old__ Objective-C code*? **Not much.** Despite these issues, I decided to let it be for the moment so that I could continue working and give some thought to a *swifter* design. I continued building out my model classes, standing up my core data stack, and writing unit tests. Much to my surprise, using the extension functions above crashed when running my unit tests. I ran the same code from the Application Target and everything was fine. After more investigation, I realized that I had just found a Swift compiler [bug](http://openradar.appspot.com/19368054). You can find an [example project](https://github.com/jessesquires/rdar-19368054) on GitHub that exhibits the bug. The issue is that the following function incorrectly returns `nil` in a project's Test Target. -{% highlight swift %} +```swift class func insertNewObjectForEntityForName(_ entityName: String, inManagedObjectContext context: NSManagedObjectContext) -> AnyObject @@ -89,7 +89,7 @@ class func insertNewObjectForEntityForName(_ entityName: String, // Returns nil in Test Target let person = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: context) as? Person -{% endhighlight %} +``` So much for revisiting these functions later. I could continue using them in the Application Target, but I would still need to find a fix for initializing managed objects in the Test Target. This isn't ideal. I would rather have a single solution that works in both targets. Back to the drawing board. @@ -105,7 +105,7 @@ Let's reiterate what we are trying to achieve. We want: The solution that meets all the criteria above is a convenience initializer: -{% highlight swift %} +```swift class Person: NSManagedObject { @@ -116,7 +116,7 @@ class Person: NSManagedObject { } -{% endhighlight %} +``` This is very similar to the original class factory function in the extension. It receives a context and returns a managed object. Regarding (2), it is very clear how this addresses the problematic `NSEntityDescription` class function. In Swift, an initializer is guaranteed to return a non-nil, typed instance, whereas `insertNewObjectForEntityForName(_, inManagedObjectContext:)` returns `AnyObject`. We avoid having to cast the return value altogether. diff --git a/_posts/2015-02-17-better-coredata-models-in-swift.md b/_posts/2015-02-17-better-coredata-models-in-swift.md index 22a52891..240f3961 100644 --- a/_posts/2015-02-17-better-coredata-models-in-swift.md +++ b/_posts/2015-02-17-better-coredata-models-in-swift.md @@ -13,7 +13,7 @@ image: half_width: false --- -As I continue my work with [Core Data](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html) and [Swift](http://www.apple.com/swift/), I have been trying to find ways to make Core Data **better**. Among my goals are clarity and safety, specifically regarding types. Luckily, we can harness Swift's optionals, enums, and other features to make managed objects more robust and more clear. But even with the improvements that Swift brings, there are still some drawbacks and limitations with Xcode's current toolset. +As I continue my work with [Core Data](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/) and [Swift](http://www.apple.com/swift/), I have been trying to find ways to make Core Data **better**. Among my goals are clarity and safety, specifically regarding types. Luckily, we can harness Swift's optionals, enums, and other features to make managed objects more robust and more clear. But even with the improvements that Swift brings, there are still some drawbacks and limitations with Xcode's current toolset. @@ -27,7 +27,7 @@ You can define minimum and maximum values, provide default values, mark attribut For example, imagine we have the following `Employee` class. What fields are required for a save to succeed? -{% highlight objc %} +```objc @interface Employee : NSManagedObject @@ -44,11 +44,11 @@ For example, imagine we have the following `Employee` class. What fields are req @end -{% endhighlight %} +``` By contrast, when using Swift we immediately know what properties are optional simply by looking at the code. -{% highlight swift %} +```swift class Employee: NSManagedObject { @@ -64,7 +64,7 @@ class Employee: NSManagedObject { @NSManaged var status: Int32 } -{% endhighlight %} +``` Note: Xcode does not generate Swift classes accurately when they have optional attributes. You must manually add the `?` for optional values. Further, though The Swift Programming Language guide recommends using `Int` for all integer variables, Core Data recommends using specific integer sizes and complains if you attempt to do otherwise, thus the use of `Int32` for the `status` property. @@ -72,7 +72,7 @@ This seems like a minor detail, but it's a huge win — especially when you Given this, let's review our `Employee` class. Is `middleName` important? No, let's remove it. Suppose that we know that all employees have an email address with the form: `@.com`. Do we really need to store it? No, we can write a function or computed property to generate that. Finally, let's assume that employees should be required to have an `address`. Ahh, this is looking much better now. -{% highlight swift %} +```swift class Employee: NSManagedObject { @@ -86,13 +86,13 @@ class Employee: NSManagedObject { @NSManaged var status: Int32 } -{% endhighlight %} +``` ### Taking advantage of `typealias` Another Swift feature we can use is a [type alias declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID361), which allows a new name to refer to an existing type. For an `Employee`, it could be very helpful to work with a `Salary` type instead of an `NSDecimalNumber` type. In the depths of the codebase, there may be operations on `NSDecimalNumber` values where it is not clear what those values represent. A `typealias` makes our model much more descriptive and allows us to operate on values of a much more expressive `Salary` type. -{% highlight swift %} +```swift class Employee: NSManagedObject { // other properties... @@ -102,19 +102,19 @@ class Employee: NSManagedObject { @NSManaged var salary: Salary } -{% endhighlight %} +``` We can then write functions that receive and return an `Employee.Salary` type. Such functions can retain their brevity, while maximizing their clarity. -{% highlight swift %} +```swift func computeRaise(salary: Employee.Salary) -> Employee.Salary -{% endhighlight %} +``` As noted in [objc.io](http://www.objc.io), *we can take this one step further* by using a [wrapper type](http://www.objc.io/snippets/8.html). To do this with an `NSManagedObject` subclass, we'll need to do some wrapping and unwrapping (no pun intended). First, the original property in Core Data should be marked as `private`. Then we can use a computed property for the new wrapper type that transforms the private property value to and from the wrapper value. This is a bit of work, but the clarity and safety we receive in return are well worth it. -{% highlight swift %} +```swift struct Salary { let amount: NSDecimalNumber @@ -138,7 +138,7 @@ class Employee: NSManagedObject { // Usage employee.salary = Salary(amount:10000.0) -{% endhighlight %} +``` Unfortunately, for fetch requests you still need to use the underlying private property name, `salaryAmount`. This is because Core Data doesn't know about the `salary` computed property, nor the `Salary` type. However, I think the naming conventions used here minimize confusion. That is, `salary.amount` corresponds to the private `salaryAmount`. @@ -148,7 +148,7 @@ It is not uncommon for a model object to encode some type of state as an `enum`. Let's see what this would look like for the `status` property in the `Employee` class. -{% highlight swift %} +```swift enum EmployeeStatus: Int32 { case ReadyForHire, Hired, Retired, Resigned, Fired, Deceased @@ -172,7 +172,7 @@ class Employee: NSManagedObject { // Usage employee.status = .Hired -{% endhighlight %} +``` Note: Just as in the previous example, for fetch requests you would still need to use the private property name, `statusValue`. diff --git a/_posts/2015-03-31-functional-notifications.md b/_posts/2015-03-31-functional-notifications.md index a8279acd..64f3ab6c 100644 --- a/_posts/2015-03-31-functional-notifications.md +++ b/_posts/2015-03-31-functional-notifications.md @@ -15,7 +15,7 @@ The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is a power A while back, [objc.io](http://www.objc.io) posted functional [snippet 16](http://www.objc.io/snippets/16.html), on *Typed Notification Observers*. I had already been working on a generic, reusable way to observe notifications in iOS, but this snippet really pointed me in the right direction. One major motivation here is to remove the boilerplate of handling notifications. A typical example would be a view controller that registers to observe a notification and implements an instance method to be called when the notification is received. -{% highlight objc %} +```objc - (void)viewDidLoad { [super viewDidLoad]; @@ -36,7 +36,7 @@ A while back, [objc.io](http://www.objc.io) posted functional [snippet 16](http: // handle notification } -{% endhighlight %} +``` This is problematic for a few reasons. @@ -51,7 +51,7 @@ Say hello to [JSQNotificationObserverKit](https://github.com/jessesquires/JSQNot We begin by creating a `Notification`. This struct has two type parameters: a value `V` and sender `S`. The type of value `V` that the notification sends is a [phantom type](http://www.objc.io/snippets/13.html), while `S` is the type of sender associated with the notification. A `Notification` also has a `name` property and an optional `sender` property. -{% highlight swift %} +```swift // 1. Suppose we have a UIView that posts a notification when its size changes let myView = UIView() @@ -59,11 +59,11 @@ let myView = UIView() // 2. This notification posts a CGSize value from a UIView sender let notification = Notification(name: "NewViewSizeNotif", sender: myView) -{% endhighlight %} +``` Next, we create our `NotificationObserver`, which is initialized with the notification described above and a closure to be called when the notification is received. Instantiating this observer automatically adds it to `NSNotificationCenter` for the notification `name` and `sender` specified by the `Notification` function parameter. Because `NotificationObserver` has the same type parameters as `Notification`, it can *only* observe that *specific* kind of notification. -{% highlight swift %} +```swift // 3. This observer listens for the notification described above var observer: NotificationObserver? @@ -73,25 +73,25 @@ observer = NotificationObserver(notification: notification) { (value: CGSize, se // handle notification } -{% endhighlight %} +``` Finally, we post the notification using the `postNotification(_:value:)` function. Again, this function has the same type parameters as `Notification`, which enforces sending a value of the type specified by the phantom type of `Notification`. In this example, we can **only** send a `CGSize` as the value. Anything else would result in a compiler error. -{% highlight swift %} +```swift // 5. Post the notification with the updated CGSize value postNotification(notification, value: CGSizeMake(200, 200)) -{% endhighlight %} +``` When the observer is set to `nil` (when it is deallocated), then it is removed from `NSNotificationCenter`. -{% highlight swift %} +```swift // 6. Unregister observer, stop listening for notifications observer = nil -{% endhighlight %} +``` That's all. Each of the aforementioned issues have been resolved. Registering and unregistering for a notification is now as simple as creating and destroying an observer object. The code for the registration and handling of the notification is all in one place. We have type-safety, and a reusable solution for the rest of our app. @@ -108,7 +108,7 @@ A notification can be configured in 4 different ways: For notifications without a sender, or for which the observer does not care about the sender, we can specify a sender of type `AnyObject`. When we initialize a `Notification`, we can omit the `sender` parameter which defaults to `nil`. The semantics here are great. *Any object* can send this notification, it does not matter to the observer. -{% highlight swift %} +```swift let myValue = MyValueType() @@ -116,17 +116,17 @@ let notification = Notification(name: "Notification") postNotification(notification, value: myValue) -{% endhighlight %} +``` For notifications without a value, we simply specify a value type of `Void`. Then when the notification is posted we send the empty tuple, `()`. Remember, the empty tuple is equivalent to `Void`. -{% highlight swift %} +```swift let notification = Notification(name: "Notification", sender: MyObject) postNotification(notification, value: ()) -{% endhighlight %} +``` From here, it is easy to see how we can construct and post a notification with neither a value nor a sender. Furthermore, the value type could be a `Dictionary` which allows this API to conform to the existing patterns in Cocoa. For more examples on usage, see the unit tests included with [JSQNotificationObserverKit](https://github.com/jessesquires/JSQNotificationObserverKit). diff --git a/_posts/2015-04-06-swift-failable-initializers-revisited.md b/_posts/2015-04-06-swift-failable-initializers-revisited.md index 42f6e3ab..824e0bd2 100644 --- a/_posts/2015-04-06-swift-failable-initializers-revisited.md +++ b/_posts/2015-04-06-swift-failable-initializers-revisited.md @@ -7,7 +7,7 @@ title: Failable initializers, revisited subtitle: Functional approaches to avoid Swift's failable initializers --- -In a [previous](/swift-failable-initializers/) post, I discussed how Swift's [failable initializers](https://developer.apple.com/swift/blog/?id=17) could be problematic. Specifically, I argued that their ease of use could persuade or encourage us to revert to old (bad) Objective-C habits of returning `nil` from `init`. Initialization is usually *not the right place* to fail. We should aim to avoid optionals as much as possible to reduce having to handle this absence of values. Recently, **@danielgomezrico** asked a great [question](https://github.com/jessesquires/jessesquires.com/issues/8) about a possible use case for a failable initializer — parsing JSON. [Given](http://owensd.io/2014/06/18/json-parsing.html) [this](http://chris.eidhof.nl/posts/json-parsing-in-swift.html) problem's [popularity](https://github.com/SwiftyJSON/SwiftyJSON) in the Swift community, I thought sharing my response here would be helpful. +In a [previous]({{ site.url }}{% post_url 2014-10-22-swift-failable-initializers %}) post, I discussed how Swift's [failable initializers](https://developer.apple.com/swift/blog/?id=17) could be problematic. Specifically, I argued that their ease of use could persuade or encourage us to revert to old (bad) Objective-C habits of returning `nil` from `init`. Initialization is usually *not the right place* to fail. We should aim to avoid optionals as much as possible to reduce having to handle this absence of values. Recently, **@danielgomezrico** asked a great [question](https://github.com/jessesquires/jessesquires.com/issues/8) about a possible use case for a failable initializer — parsing JSON. [Given](http://owensd.io/2014/06/18/json-parsing.html) [this](http://chris.eidhof.nl/posts/json-parsing-in-swift.html) problem's [popularity](https://github.com/SwiftyJSON/SwiftyJSON) in the Swift community, I thought sharing my response here would be helpful. @@ -15,7 +15,7 @@ In a [previous](/swift-failable-initializers/) post, I discussed how Swift's [fa Suppose we have a JSON object that contains the data for a model object. Should we write a failable initializer for this model that receives the JSON, and fails if there is problem with parsing or validation? This scenario would look similar to the following: -{% highlight swift %} +```swift // Some JSON for MyModel struct JSON { @@ -39,11 +39,11 @@ else { // failure } -{% endhighlight %} +``` This rather straightforward, but is using `init?` the best solution? There are some issues here that we need to address. First, the model *knows* **everything**. It knows that JSON is a thing, that JSON exists. It shouldn't. A model should be a dumb container (preferably immutable) that holds data. Even worse, the model knows *how to parse* the JSON. This means the model knows how JSON is generally structured and how it works, but more specifically it knows how *itself is represented as JSON*. -What if the structure or keys in the JSON change? Then we would have to update our model. What if we are using [Core Data](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html), and our model is an `NSManagedObject` subclass? Then we would have to stand up an **entire** Core Data stack just to unit test the JSON parsing. What if the service from which we receive the JSON changes and instead we receive XML? Then we would need a new initializer, `init?(xml: XML)`, and the model would know all about XML. +What if the structure or keys in the JSON change? Then we would have to update our model. What if we are using [Core Data](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/), and our model is an `NSManagedObject` subclass? Then we would have to stand up an **entire** Core Data stack just to unit test the JSON parsing. What if the service from which we receive the JSON changes and instead we receive XML? Then we would need a new initializer, `init?(xml: XML)`, and the model would know all about XML. This design has put our model in a fragile position. @@ -53,7 +53,7 @@ The issues above can be addressed by removing the model's dependency on JSON (or The first step is creating a generic validator object. We'll use a [phantom type](http://www.objc.io/snippets/13.html) to ensure that a validator can only validate the JSON for a specific type of model. We initialize the validator with a closure that receives JSON and returns a `Bool` indicating whether or not it is valid. This closure is saved as a property on the validator. -{% highlight swift %} +```swift struct JSONValidator { @@ -76,13 +76,13 @@ let validator = JSONValidator { (json) -> Bool in return true } -{% endhighlight %} +``` The combination of a phantom type and a closure property enable us to construct many unique validators, while maintaining a single generic interface through which validation occurs. In other words, we do not have to create many different concrete validators (or validator subclasses) for many different models. Additionally, in this example you can see how this brings type-safety and readability to the validator. We know that this validator is for `MyModel` instances. Next, we'll define a JSON parser protocol, and implement a concrete parser. The protocol will allow us to reference parsers throughout our code in a generic way, while enabling each concrete parser to know about parsing a specific type of model. The parser will receive JSON, parse it, and return a model. We'll also add a new (more proper) designated initializer to `MyModel` that uses [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection) and remove the old one, `init?(json: JSON)`. This parser assumes that the JSON has already been validated. -{% highlight swift %} +```swift struct MyModel { let name: String @@ -105,11 +105,11 @@ struct MyModelParser: JSONParserType { } } -{% endhighlight %} +``` Now we can put everything together. Once we receive JSON, we can validate it. If validation fails, then we are finished and there is no need to continue. With this solution, no failable initializers are required. -{% highlight swift %} +```swift let json = JSON(data: dataFromServer) @@ -127,11 +127,11 @@ let parser = MyModelParser() let myModel = parser.parseJSON(json) -{% endhighlight %} +``` This is much better. We have divided the problem into smaller subproblems and addressed each one individually. Even better, we can now unit test each component in isolation. However, because we are using Swift we can make this better. We can combine all the steps above into a top-level generic function. This function receives each of the components above — JSON, a validator, and a parser — and returns a model. -{% highlight swift %} +```swift func parse(json: JSON, validator: JSONValidator, parser: P) -> T? { if !validator.isValid(json) { @@ -149,7 +149,7 @@ else { // failure } -{% endhighlight %} +``` Suffering from [angle-brack-T blindness](http://inessential.com/2015/02/04/random_swift_things)? Me too. Let's break this down. The type parameter `T` specifies the model type. The validator must be a validator for `T`, and the function returns an optional `T?`. The type parameter `P` specifies the parser type, and the `where` clause enforces that the parser `P` parses models of type `T`. If validation fails, then the function returns `nil`, otherwise it will parse the JSON and return a model. diff --git a/_posts/2015-07-19-swift-namespaced-constants.md b/_posts/2015-07-19-swift-namespaced-constants.md index 718c5029..4eb532b3 100644 --- a/_posts/2015-07-19-swift-namespaced-constants.md +++ b/_posts/2015-07-19-swift-namespaced-constants.md @@ -30,7 +30,7 @@ We are all familiar with handling assets, particularly icons, using the `UIImage In the past, we strove to avoid [stringly-typed](https://corner.squareup.com/2014/02/objc-codegenutils.html) Objective-C in Cocoa by creating constants or categories. But rather than apply these same techniques in Swift with an `extension`, we can do something more sophisticated. -{% highlight swift %} +```swift enum Icon: String { case Music @@ -48,7 +48,7 @@ enum Icon: String { let icon = Icon.Music.image() // "music" icon let iconSelected = Icon.Music.image(selected: true) // "music-selected" icon -{% endhighlight %} +``` In this example, we are using the new [default enum naming](http://ericasadun.com/2015/07/08/swift-new-stuff-in-xcode-7-beta-3/) for enums with a string raw type. This alone makes a huge difference — no explicit, hard-coded strings at all! We now have constants for all of our icon names, and the `image(selected:)` method will return the correct `UIImage`. @@ -58,7 +58,7 @@ You may be thinking that we could implement an extension on `UIImage` instead. B Another common use case for constants, or a Swift extension are for the custom colors in an app. It would be nice to be able to use an enum in this scenario, but an enum raw value type must be a **value type** — sorry `UIColor`. Alternatively, we can use structs and nested structs. -{% highlight swift %} +```swift struct ColorPalette { static let Red = UIColor(red: 1.0, green: 0.1491, blue: 0.0, alpha: 1.0) @@ -76,7 +76,7 @@ struct ColorPalette { let red = ColorPalette.Red let darkGray = ColorPalette.Gray.Dark -{% endhighlight %} +``` Again, we should not add our custom colors to `UIColor` globally via an extension. For colors, using an extension presents even more challenges regarding naming. For example if you have a custom red color, you cannot name the method `redColor()` because `UIColor` already defines this class method. Do you name your method `red()`? That's kind of awkward. Do you prefix the method name like you would in Objective-C, `jsq_redColor()`? That's *more* awkward in Swift. Given light and dark versions of colors, do you use `darkPurple()`, or `purpleDark()`? If you have many dark and light variants, it might be better to use the `{colorName}{variant}` naming convention. Regardless, everyone on your team will have different opinions on naming — and they will *__all__ be great!* diff --git a/_posts/2015-07-26-swift-enumerations-and-equatable.md b/_posts/2015-07-26-swift-enumerations-and-equatable.md index 901141ec..fa60343f 100644 --- a/_posts/2015-07-26-swift-enumerations-and-equatable.md +++ b/_posts/2015-07-26-swift-enumerations-and-equatable.md @@ -14,7 +14,7 @@ Recently, I came across a **case** (*pun intended*) where I needed to compare tw As you likely know, if you want to compare two instances of a type in Swift, then that type must conform to the [Equatable](http://nshipster.com/swift-comparison-protocols/) protocol. In other words, you must define the `==` operator for the type. If the enumeration does not have associated values or if it has a raw-value type, then you get the `==` operator for free from the Swift [Standard Library](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/index.html). For example: -{% highlight swift %} +```swift // With a raw-value // Double conforms to Equatable @@ -39,11 +39,11 @@ enum CompassPoint: Equatable { CompassPoint.North == CompassPoint.North // true CompassPoint.South == CompassPoint.East // false -{% endhighlight %} +``` Comparing cases in these enumerations works *out-of-the-box* because enumerations that have cases of a raw-value type implicitly conform to the [RawRepresentable](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_RawRepresentable_Protocol/index.html#//apple_ref/swift/intf/s:PSs16RawRepresentable) protocol. The Swift Standard Library provides implementations of the `==` operator for `RawRepresentable` types and generic `T` types. -{% highlight swift %} +```swift // Used to compare 'Math' enum func ==(lhs: T, rhs: T) -> Bool @@ -51,11 +51,11 @@ func ==(lhs: T, rhs: T) -> Bo // Used to compare 'CompassPoint' enum func ==(lhs: T?, rhs: T?) -> Bool -{% endhighlight %} +``` It is easy to see how and why this works. For the `RawRepresentable` type, as long as the `rawValue` conforms to `Equatable`, then all this function has to do is compare the raw-value from each type. Without a raw-value, the different enumeration members are fully-fledged values in their own right. But if the some cases of the enumeration have [associated values](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID148), then you must implement the `==` operator yourself. Consider the following example. -{% highlight swift %} +```swift enum Barcode { case UPCA(Int, Int) @@ -65,11 +65,11 @@ enum Barcode { // Error: binary operator '==' cannot be applied to two Barcode operands Barcode.QRCode("code") == Barcode.QRCode("code") -{% endhighlight %} +``` If you are well versed in Swift's pattern matching capabilities, then conforming to `Equatable` is very straightforward. -{% highlight swift %} +```swift extension Barcode: Equatable { } @@ -93,6 +93,6 @@ Barcode.QRCode("code") == Barcode.QRCode("code") // true Barcode.UPCA(1234, 1234) == Barcode.UPCA(4567, 7890) // false Barcode.None == Barcode.None // true -{% endhighlight %} +``` Even with Swift 2.0, the syntax is a somewhat difficult to read and difficult to remember. We must pattern match on each case and then unpack the associated values (if any) to compare them directly. That's it! Now we can compare our custom enumerations. diff --git a/_posts/2015-10-14-UIKit-changes-in-iOS-9.md b/_posts/2015-10-14-UIKit-changes-in-iOS-9.md index 4e5f90cc..01a20199 100644 --- a/_posts/2015-10-14-UIKit-changes-in-iOS-9.md +++ b/_posts/2015-10-14-UIKit-changes-in-iOS-9.md @@ -25,7 +25,7 @@ The issue is that a non-zeroing reference ends up pointing to invalid memory (be Why do these details about weak references matter? Because up to iOS 9, UIKit views that have a `delegate` or `dataSource` property have been declared as the following. -{% highlight swift %} +```swift // UITableView iOS 8 and below @property(nonatomic, assign) id dataSource @@ -35,7 +35,7 @@ Why do these details about weak references matter? Because up to iOS 9, UIKit vi @property(nonatomic, assign) id delegate @property(nonatomic, assign) id dataSource -{% endhighlight %} +``` Note: this extends well beyond UITableView and UICollectionView. UIBarButtonItem.target is assign. UIGestureRecognizer.delegate is assign. UIActionSheet.delegate is assign. UIAccelerometer.delegate is assign. The list goes on, everywhere in UIKit. @@ -49,7 +49,7 @@ For correctness, you should be setting these to `nil` in `dealloc`. In the comme As of iOS 9, the aforementioned APIs have changed. In fact, all of UIKit looks like it [has been audited](https://developer.apple.com/library/prerelease/ios/releasenotes/General/iOS90APIDiffs/Objective-C/UIKit.html). Everywhere I looked, `assign` was replaced with `weak, nullable`. -{% highlight swift %} +```swift // UITableView iOS 9 @property(nonatomic, weak, nullable) id dataSource @@ -59,6 +59,6 @@ As of iOS 9, the aforementioned APIs have changed. In fact, all of UIKit looks l @property(nonatomic, weak, nullable) id delegate @property(nonatomic, weak, nullable) id dataSource -{% endhighlight %} +``` I can't say for certain, but my guess is that we can thank Swift for this. Swift was the impetus for [nullability annotations](https://developer.apple.com/swift/blog/?id=25) and generics in Objective-C, and we know the teams at Apple have been [working hard](https://developer.apple.com/swift/blog/?id=31) to update all of the Cocoa frameworks with these features. Maybe `assign` affects interoperability with Swift? In any case, non-zeroing weak references are finally gone. As developers, we can finally get some sleep. diff --git a/_posts/2015-10-25-building-data-sources-in-swift.md b/_posts/2015-10-25-building-data-sources-in-swift.md index a1be9202..ecc6de62 100644 --- a/_posts/2015-10-25-building-data-sources-in-swift.md +++ b/_posts/2015-10-25-building-data-sources-in-swift.md @@ -39,7 +39,7 @@ As mentioned above, I want to avoid the baggage of `@objc` and prevent `NSObject 4. **`DataSourceProvider` —** Data source provider objects are composed of an array of sections, a cell factory, and a bridged data source. (And for collection views, there's also a supplementary view factory.) A provider object orchestrates and mediates the communications between its constituent parts, which know nothing about each other. Finally, as the name suggests, it provides the data source for a table view or a collection view, which happens via its private bridged data source instance. To clients, it looks like this: -{% highlight swift %} +```swift // TableViewDataSourceProvider public var dataSource: UITableViewDataSource { @@ -51,13 +51,13 @@ public var dataSource: UICollectionViewDataSource { return bridgedDataSource } -{% endhighlight %} +``` ### Putting it all together Let's take a look at how this works in practice. Here's an example for a simple collection view. -{% highlight swift %} +```swift let section0 = CollectionViewSection(items: ViewModel(), ViewModel(), ViewModel()) let section1 = CollectionViewSection(items: ViewModel(), ViewModel()) @@ -80,13 +80,13 @@ self.provider = CollectionViewDataSourceProvider( self.collectionView.dataSource = provider.dataSource -{% endhighlight %} +``` First, we populate our section objects with our models. Then we create our cell and header view factories. Finally, we pass all of these instances to our data source provider. That's all. The collection view will now display all of our data. The result is an elegant, composed, protocol-oriented, and testable system. You can independently test your models, test that each factory returns correctly configured views, and test that the `provider.dataSource` accurately responds to the `UICollectionViewDataSource` methods. Using this framework with table views follows similarly, with the main exception being that table views do not have supplementary views. Also remember that the `CollectionViewDataSourceProvider` only speaks to protocols — not the concrete objects used in the example above. Its signature is the following. -{% highlight swift %} +```swift public final class CollectionViewDataSourceProvider < SectionInfo: CollectionViewSectionInfo, @@ -94,7 +94,7 @@ public final class CollectionViewDataSourceProvider < SupplementaryViewFactory: CollectionSupplementaryViewFactoryType where CellFactory.Item == SectionInfo.Item, SupplementaryViewFactory.Item == SectionInfo.Item> -{% endhighlight %} +``` Do not be afraid! Before Brent Simmons accuses me of contributing to [angle-bracket-T blindness](http://inessential.com/2015/02/04/random_swift_things), let me explain. There are three generic type parameters. We specify that these three types must conform to the `CollectionViewSectionInfo`, `CollectionViewCellFactoryType`, and `CollectionSupplementaryViewFactoryType` protocols. Finally, the `where` clause specifies that each object must deal with the same kind of model objects (`Item`). This prevents us from trying to use a section of `ModelA` with a cell factory of `ModelB`. diff --git a/_posts/2015-12-06-swift-open-source.md b/_posts/2015-12-06-swift-open-source.md index 33eac715..5c229d3d 100644 --- a/_posts/2015-12-06-swift-open-source.md +++ b/_posts/2015-12-06-swift-open-source.md @@ -33,15 +33,15 @@ For the past few days I have been watching the repositories on [GitHub](https:// - There has been close to ~400 pull requests across all of the repos. Many of them accepted and merged. -- After the initial Swift announcement at [WWDC 2014](https://developer.apple.com/videos/play/wwdc2014-402/), I think we all noticed how active the Swift team was on twitter, answering questions and more — [Chris Lattner](https://twitter.com/clattner_llvm), [Joe Groff](https://twitter.com/jckarter), and [Jordan Rose](https://twitter.com/UINT_MIN) to name a few. Turns out some tweets [resulted](https://github.com/apple/swift/commit/666646fee95bc75ca81e1dc5131989d56bfb0742) in *immediate* bug fixes! šŸ˜„ +- After the initial Swift announcement at [WWDC 2014](https://developer.apple.com/videos/play/wwdc2014-402/), I think we all noticed how active the Swift team was on twitter, answering questions and more — [Chris Lattner](https://twitter.com/clattner_llvm), [Joe Groff](https://twitter.com/jckarter), and [Jordan Rose](https://twitter.com/UINT_MIN) to name a few. Turns out some tweets [resulted](https://github.com/apple/swift/commit/666646fee95bc75ca81e1dc5131989d56bfb0742) in *immediate* bug fixes! - Remember that [partnership](https://www.apple.com/pr/library/2014/07/15Apple-and-IBM-Forge-Global-Partnership-to-Transform-Enterprise-Mobility.html) with [Apple and IBM](http://www.apple.com/business/mobile-enterprise-apps/)? Then it should not be a surprise that IBM seems to be [very invested](https://developer.ibm.com/swift/2015/12/03/introducing-the-ibm-swift-sandbox/) in server-side Swift. It looks like there is growing momentum behind using Swift on the server. -- Chris Lattner is [merging pull requests](https://github.com/apple/swift/pull/166) at 10pm on Saturday. šŸ˜† +- Chris Lattner is [merging pull requests](https://github.com/apple/swift/pull/166) at 10pm on Saturday. - We know exactly [what to expect](https://github.com/apple/swift-evolution) for Swift 3.0! No more keynote surprises. -- The [++ and -- operators will be removed](https://github.com/apple/swift-evolution/blob/master/proposals/0004-remove-pre-post-inc-decrement.md) from Swift 3.0. And thanks to [Erica Sadun](https://twitter.com/ericasadun), so will [C-style for-loops](https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md). She submitted this proposal on day two! šŸ‘ +- The [++ and -- operators will be removed](https://github.com/apple/swift-evolution/blob/master/proposals/0004-remove-pre-post-inc-decrement.md) from Swift 3.0. And thanks to [Erica Sadun](https://twitter.com/ericasadun), so will [C-style for-loops](https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md). She submitted this proposal on day two! - Chris Lattner [commits](https://github.com/apple/swift/commit/22c3aa0588d2df1a207dcbad85946bab7976894c) *"Pull some ancient history off an internal wiki page for possible historical interest."* What?! Yes please! Nerd alert. @@ -49,11 +49,11 @@ For the past few days I have been watching the repositories on [GitHub](https:// - It looks like there's a [good chance](https://github.com/apple/swift-evolution/pull/33/files) that `typealias` will be replaced with `associated` for associated type declarations. -- [Jacob Bandes-Storch](https://twitter.com/jtbandes) has [submitted](https://github.com/apple/swift/pull/253) [two](https://github.com/apple/swift/pull/272) pull requests that fix a total of over 400 crashes. 😲 +- [Jacob Bandes-Storch](https://twitter.com/jtbandes) has [submitted](https://github.com/apple/swift/pull/253) [two](https://github.com/apple/swift/pull/272) pull requests that fix a total of over 400 crashes. - The Swift team seems [very keen](https://twitter.com/clattner_llvm/status/673162286127714304) on getting the community involved. No contribution is too small! -- Much of the [swift-corelibs-foundation](https://github.com/apple/swift-corelibs-foundation) framework is currently [unimplemented](https://github.com/apple/swift-corelibs-foundation/search?utf8=āœ“&q=NSUnimplemented). There seems to be a lot of low hanging fruit. I wonder if this is intentional to encourage contributions, or if it is the result of a tight deadline? +- Much of the [swift-corelibs-foundation](https://github.com/apple/swift-corelibs-foundation) framework is currently [unimplemented](https://github.com/apple/swift-corelibs-foundation/search?q=NSUnimplemented). There seems to be a lot of low hanging fruit. I wonder if this is intentional to encourage contributions, or if it is the result of a tight deadline? - The [initial checkin](https://github.com/apple/swift/commit/afc81c1855bf711315b8e5de02db138d3d487eeb) from 2010 was actually revision 4 and imported from an internal SVN repo. "Swift SVN r4". You will notice the following in the header comments: *"This source file is part of the Swift.org open source project. Copyright (c) 2014 - 2015 Apple Inc."* I have three theories: 1. Commit history was edited and cleaned up before being published on GitHub. diff --git a/_posts/2015-12-10-open-source-swift-weekly-1.md b/_posts/2015-12-10-open-source-swift-weekly-1.md index 2a38f751..bf3788cc 100644 --- a/_posts/2015-12-10-open-source-swift-weekly-1.md +++ b/_posts/2015-12-10-open-source-swift-weekly-1.md @@ -15,30 +15,30 @@ It looks many developers in the community enjoyed my [previous post]({{ site.url - [Manav Gabhawala](https://twitter.com/ManavGabhawala) submitted an [interesting proposal](https://github.com/apple/swift-evolution/pull/37) to add implicit initializers to Swift. In particular, this would address the verbosity of converting between number types. However, as pointed out on the [mailing list discussion](https://lists.swift.org/pipermail/swift-evolution/2015-December/000352.html) there are safety and precision concerns. -- [Alex Denisov](https://twitter.com/1101_debian) submitted a [pull request](https://github.com/apple/swift/pull/295) that fixes 323 crashes. 😲 +- [Alex Denisov](https://twitter.com/1101_debian) submitted a [pull request](https://github.com/apple/swift/pull/295) that fixes 323 crashes. - Not very good at [using git](https://github.com/apple/swift-evolution/pull/39)? Worry not! Lots of [cool people](https://github.com/apple/swift-evolution/pull/34#issuecomment-162693826) aren't that great at using it either. The message here: do not let this deter you from contributing! - Chris Lattner tends to [fix](https://github.com/apple/swift/commit/4ebb461d634964f0399d63b3264d4090451c77fd) [radars](https://github.com/apple/swift/commit/5dded3f3523e9bd6ea45d0b6ffe5068a59d03a3f) late at night. -- [Brian Gesiak](https://twitter.com/modocache), creator of [Quick](https://github.com/Quick/Quick), asks [*who tests the tests?*](https://lists.swift.org/pipermail/swift-corelibs-dev/2015-December/000018.html) after noticing that the [xctest](https://github.com/apple/swift-corelibs-xctest) framework isn't itself tested. Testing a testing framework sounds funny, but some important [bugs](https://github.com/apple/swift-corelibs-xctest/commit/ce4c98bc58763d49db474703d005ba9c479cac3a) have already been found. [FIXME](https://github.com/apple/swift/blob/b53ff3b58053407f380d09770d2e2069e02d6ff5/utils/build-script-impl#L1957). 😳 +- [Brian Gesiak](https://twitter.com/modocache), creator of [Quick](https://github.com/Quick/Quick), asks [*who tests the tests?*](https://lists.swift.org/pipermail/swift-corelibs-dev/2015-December/000018.html) after noticing that the [xctest](https://github.com/apple/swift-corelibs-xctest) framework isn't itself tested. Testing a testing framework sounds funny, but some important [bugs](https://github.com/apple/swift-corelibs-xctest/commit/ce4c98bc58763d49db474703d005ba9c479cac3a) have already been found. [FIXME](https://github.com/apple/swift/blob/b53ff3b58053407f380d09770d2e2069e02d6ff5/utils/build-script-impl#L1957). - In case you missed it, currying [will be removed](https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md) from Swift 3.0. ([What is currying](https://robots.thoughtbot.com/introduction-to-function-currying-in-swift)?) - [David Owens](https://twitter.com/owensd) submitted a [proposal](https://github.com/apple/swift-evolution/pull/26) to add type annotations to `throws`. When Swift's error-handling model was first announced, the lack of explicit error types was a common criticism. There's a [good discussion](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001117.html) on the mailing list. You can also read the original [Error Handling Rationale and Proposal](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst). -- Swift now has almost 200 [contributors](https://github.com/apple/swift/graphs/contributors) and over 230 pull requests have been [merged](https://github.com/apple/swift/pulls?utf8=āœ“&q=is%3Apr+is%3Amerged+). +- Swift now has almost 200 [contributors](https://github.com/apple/swift/graphs/contributors) and over 230 pull requests have been [merged](https://github.com/apple/swift/pulls?q=is%3Apr+is%3Amerged+). -- Last week I mentioned that [Foundation](https://github.com/apple/swift-corelibs-foundation) was largely [unimplemented](https://github.com/apple/swift-corelibs-foundation/search?utf8=āœ“&q=NSUnimplemented). There's also some *really* surprising [bugs](https://github.com/apple/swift-corelibs-foundation/pull/89/files). +- Last week I mentioned that [Foundation](https://github.com/apple/swift-corelibs-foundation) was largely [unimplemented](https://github.com/apple/swift-corelibs-foundation/search?q=NSUnimplemented). There's also some *really* surprising [bugs](https://github.com/apple/swift-corelibs-foundation/pull/89/files). -- [Andrew Naylor](https://github.com/argon) ambitiously implements [NSJSONSerialization](https://github.com/apple/swift-corelibs-foundation/pull/54). šŸ‘ +- [Andrew Naylor](https://github.com/argon) ambitiously implements [NSJSONSerialization](https://github.com/apple/swift-corelibs-foundation/pull/54). - [Jacob Bandes-Storch](https://twitter.com/jtbandes) submitted a [proposal](https://github.com/apple/swift-evolution/pull/44) that aims to greatly improve the bridging of C APIs. -- There's an [interesting discussion](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/000873.html) on the mailing lists to make classes and methods `final` by default. Anything that discourages or prevents subclassing is [fine by me](https://twitter.com/jesse_squires/status/664588682997964800). 😊 +- There's an [interesting discussion](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/000873.html) on the mailing lists to make classes and methods `final` by default. Anything that discourages or prevents subclassing is [fine by me](https://twitter.com/jesse_squires/status/664588682997964800). - The Swift Programming Language iBook (ePub) is available for *direct download* on Swift.org (instead of only the iBook Store) and is now under a [Creative Commons Attribution 4.0 International (CC BY 4.0) License](https://swift.org/documentation/)! Translations [would be great](https://twitter.com/clattner_llvm/status/674454905449373696). -- Programming is little more than a ["nights and weekends" hobby](https://twitter.com/clattner_llvm/status/674254974629502976) for Chris Lattner. šŸ˜‚ +- Programming is little more than a ["nights and weekends" hobby](https://twitter.com/clattner_llvm/status/674254974629502976) for Chris Lattner. **That's it for this week!** [Subscribe]({{ site.url }}{{ site.feeds.rss }}) or [follow me]({{ site.social_links.twitter }}) to stay up-to-date! diff --git a/_posts/2015-12-17-open-source-swift-weekly-2.md b/_posts/2015-12-17-open-source-swift-weekly-2.md index 00414edd..70a75b68 100644 --- a/_posts/2015-12-17-open-source-swift-weekly-2.md +++ b/_posts/2015-12-17-open-source-swift-weekly-2.md @@ -21,9 +21,9 @@ One clarification from last week — currying will not removed completely, [ ### Commits and pull requests -[Slava Pestov](https://github.com/slavapestov) pushed [a commit](https://github.com/apple/swift/commit/c258f991f64a431da57fc79b66e879e5062fba3b) that *fixed [91 percent](https://github.com/apple/swift/commit/c258f991f64a431da57fc79b66e879e5062fba3b#commitcomment-14971959) of the outstanding compiler crashers.* 😲 +[Slava Pestov](https://github.com/slavapestov) pushed [a commit](https://github.com/apple/swift/commit/c258f991f64a431da57fc79b66e879e5062fba3b) that *fixed [91 percent](https://github.com/apple/swift/commit/c258f991f64a431da57fc79b66e879e5062fba3b#commitcomment-14971959) of the outstanding compiler crashers.* -[Dominique d'Argent](https://github.com/nubbel) introduced the first [unicode variable name](https://github.com/apple/swift-corelibs-foundation/pull/93#discussion_r47160608) in his implementation of `NSAffineTransform`. This is the only one that I've seen so far. I will happily buy a ā˜•ļø or šŸŗ for anyone who can successfully merge a pull request that uses šŸ’©. +[Dominique d'Argent](https://github.com/nubbel) introduced the first [unicode variable name](https://github.com/apple/swift-corelibs-foundation/pull/93#discussion_r47160608) in his implementation of `NSAffineTransform`. This is the only one that I've seen so far. I will happily buy a ☕ or 🍺 for anyone who can successfully merge a pull request that uses 💩. [Bill Abt](https://github.com/apple/swift/pull/413) and [David Grove](https://github.com/apple/swift-corelibs-libdispatch/pull/15) from IBM made significant contributions to Swift and the core libraries! As Federighi mentioned on The Talk Show, IBM *really* wants to use Swift on the server. @@ -31,17 +31,17 @@ Chris Lattner [fixed](http://github.com/apple/swift/commit/a2d9b10b64c3115c2eed7 [Daniel Duan](https://github.com/dduan) submitted a [pull request](https://github.com/apple/swift/pull/419) to optimize the `Set` collection type. The result is roughly a 42 percent speed improvement. [Whoa!](https://github.com/apple/swift/pull/419#issuecomment-164109613) -[@PracticalSwift](https://twitter.com/practicalswift) fixed [a ton](https://github.com/apple/swift/pull/561) of [typos](https://github.com/apple/swift/pull/526). šŸ˜‚ +[@PracticalSwift](https://twitter.com/practicalswift) fixed [a ton](https://github.com/apple/swift/pull/561) of [typos](https://github.com/apple/swift/pull/526). William Dillon [began support](https://github.com/apple/swift/pull/439) for ARMv7 hosts such as the Raspberry Pi, BeagleBone, and Nvidia Tegras. -Brian Gesiak [continued to pursue](https://github.com/apple/swift-corelibs-xctest/pull/14) testing the XCTest framework, and in terms of number of commits, he is now the [#3 contributor](https://github.com/apple/swift-corelibs-xctest/graphs/contributors) on corelibs-xctest. šŸ‘ +Brian Gesiak [continued to pursue](https://github.com/apple/swift-corelibs-xctest/pull/14) testing the XCTest framework, and in terms of number of commits, he is now the [#3 contributor](https://github.com/apple/swift-corelibs-xctest/graphs/contributors) on corelibs-xctest. ### Proposals The first independent Swift language evolution proposal has been [accepted](https://twitter.com/clattner_llvm/status/676472122437271552)! You can say goodbye to [C-style for-loops](https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md) and say thank you to [Erica Sadun](https://twitter.com/ericasadun). Beginning in Swift 2.2, you'll see warning if you use a C-style for-loop and it will be removed in the 3.0 release. *"For the most part, there was agreement that C-style for loops are quite rare in Swift code, and most of the existing uses would be better written as for-in loops."* Also be sure to note the two potential problems with this change as described in the [announcement](https://lists.swift.org/pipermail/swift-evolution-announce/2015-December/000001.html). -[Max Howell](https://github.com/mxcl), [Daniel Dunbar](https://github.com/ddunbar), and [Mattt Thompson](https://github.com/mattt) have prepared [a proposal](https://github.com/apple/swift-evolution/pull/51) to add testing support to the [Swift package manager](https://github.com/apple/swift-package-manager)! *"Testing is an essential part of modern software development. Tight integration of testing into the Swift Package Manager will help ensure a stable and reliable packaging ecosystem. We propose to extend our conventional package directory layout to accommodate test modules."* šŸŽ‰ +[Max Howell](https://github.com/mxcl), [Daniel Dunbar](https://github.com/ddunbar), and [Mattt Thompson](https://github.com/mattt) have prepared [a proposal](https://github.com/apple/swift-evolution/pull/51) to add testing support to the [Swift package manager](https://github.com/apple/swift-package-manager)! *"Testing is an essential part of modern software development. Tight integration of testing into the Swift Package Manager will help ensure a stable and reliable packaging ecosystem. We propose to extend our conventional package directory layout to accommodate test modules."* Max Moiseev's [proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0014-constrained-AnySequence.md) to constrain `AnySequence.init` is due for review this week. I don't see any reason why this would not be accepted. *"These constraints, in fact, should be applied to `SequenceType` protocol itself (although, that is not currently possible), as we expect every `SequenceType` implementation to satisfy them already."* diff --git a/_posts/2015-12-24-open-source-swift-weekly-3.md b/_posts/2015-12-24-open-source-swift-weekly-3.md index 991c8ddf..e187d473 100644 --- a/_posts/2015-12-24-open-source-swift-weekly-3.md +++ b/_posts/2015-12-24-open-source-swift-weekly-3.md @@ -7,7 +7,7 @@ title: "Open source Swift: weekly brief #3" subtitle: What's been happening on Swift.org? --- -As expected with the holiday season, [things are](https://lists.swift.org/pipermail/swift-corelibs-dev/Week-of-Mon-20151214/000179.html) [slowing down](https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151221/000540.html) for a bit on Swift.org. I have been traveling for the holidays as well, so this issue will be shorter than usual. If you haven't already, be sure you take some time away from coding to enjoy the holidays and [avoid burnout](https://twitter.com/chriseidhof/status/679213894343200768). šŸ˜„ Now, the weekly brief! +As expected with the holiday season, [things are](https://lists.swift.org/pipermail/swift-corelibs-dev/Week-of-Mon-20151214/000179.html) [slowing down](https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151221/000540.html) for a bit on Swift.org. I have been traveling for the holidays as well, so this issue will be shorter than usual. If you haven't already, be sure you take some time away from coding to enjoy the holidays and [avoid burnout](https://twitter.com/chriseidhof/status/679213894343200768). Now, the weekly brief! @@ -15,24 +15,24 @@ As expected with the holiday season, [things are](https://lists.swift.org/piperm [@tienex](https://github.com/tienex) submitted a [pull request](https://github.com/apple/swift/pull/608) for Linux/armv7 support. -[@practicalswift](https://github.com/practicalswift) added a ton of [test cases](https://github.com/apple/swift/pulls?utf8=āœ“&q=is%3Apr+author%3Apracticalswift+is%3Aclosed+test+case). And as of this writing, there are still a few waiting to be merged. +[@practicalswift](https://github.com/practicalswift) added a ton of [test cases](https://github.com/apple/swift/pulls?q=is%3Apr+author%3Apracticalswift+is%3Aclosed+test+case). And as of this writing, there are still a few waiting to be merged. -[@masters3d](https://github.com/masters3d) merged a [pull request](https://github.com/apple/swift-evolution/pull/72/files) to swift-evolution that documents commonly proposed changes to Swift. This is a great idea to help reduce duplicate proposals. Don't forget to [check this list](https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md) before suggesting a change on the mailing list! šŸ‘ +[@masters3d](https://github.com/masters3d) merged a [pull request](https://github.com/apple/swift-evolution/pull/72/files) to swift-evolution that documents commonly proposed changes to Swift. This is a great idea to help reduce duplicate proposals. Don't forget to [check this list](https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md) before suggesting a change on the mailing list! Doug Gregor [implemented SE-0001](https://github.com/apple/swift/commit/c8dd8d066132683aa32c2a5740b291d057937367), which *"allows (most) keywords as argument labels"*. This is a great change. When Swift was initially released, one of my Objective-C libraries used `extension:` as a [parameter name](https://github.com/jessesquires/JSQSystemSoundPlayer/issues/8) (for a file extension string) and bridging to Swift caused all kinds of problems, thus I ended up having to rename it to `fileExtension:`. Glad to see I can revert this change in Swift 2.2! Note that the keywords `var`, `let`, and `inout` are excluded from this. ### Proposals -Oisin Kidney's [proposal (SE-0008)](https://github.com/apple/swift-evolution/blob/master/proposals/0008-lazy-flatmap-for-optionals.md), *Add a Lazy flatMap for Sequences of Optionals*, has been [accepted](https://lists.swift.org/pipermail/swift-evolution-announce/2015-December/000006.html) for Swift 2.2! šŸŽ‰ +Oisin Kidney's [proposal (SE-0008)](https://github.com/apple/swift-evolution/blob/master/proposals/0008-lazy-flatmap-for-optionals.md), *Add a Lazy flatMap for Sequences of Optionals*, has been [accepted](https://lists.swift.org/pipermail/swift-evolution-announce/2015-December/000006.html) for Swift 2.2! -Kevin Ballard's [proposal (SE-0015)](https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md), *Tuple comparison operators* has also been [accepted](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/004423.html)! As of this writing, the status of the proposal on GitHub has not been updated to reflect this. Since this proposal should not affect existing code, I assume it will be included for Swift 2.2. šŸŽ‰ +Kevin Ballard's [proposal (SE-0015)](https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md), *Tuple comparison operators* has also been [accepted](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/004423.html)! As of this writing, the status of the proposal on GitHub has not been updated to reflect this. Since this proposal should not affect existing code, I assume it will be included for Swift 2.2. -Joe Groff submitted [a proposal](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003148.html) to add property behaviors to Swift. You can find [draft](https://gist.github.com/jckarter/f3d392cf183c6b2b2ac3) on GitHub. Or if you prefer to receive information via [tweet](https://twitter.com/jckarter/status/677554831003791360), there's that too. šŸ˜„ In short, the proposal outlines an extensible framework for applying various behaviors to properties, similar to `atomic` or `copy` in Objective-C. Currently, Swift has some special-purpose hardcoded behaviors, for example,`lazy`, `@NSCopying`, and `willSet`/`didSet`. This proposal aims to generalize and unify these concepts such that they are implemented via the same underlying framework and can be easily extended. Clients could even implement their own behaviors. It sounds awesome. Some example behaviors include: lazy, memoization, delayed initialization, resettable, and synchronized. Definitely worth the read! +Joe Groff submitted [a proposal](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003148.html) to add property behaviors to Swift. You can find [draft](https://gist.github.com/jckarter/f3d392cf183c6b2b2ac3) on GitHub. Or if you prefer to receive information via [tweet](https://twitter.com/jckarter/status/677554831003791360), there's that too. In short, the proposal outlines an extensible framework for applying various behaviors to properties, similar to `atomic` or `copy` in Objective-C. Currently, Swift has some special-purpose hardcoded behaviors, for example,`lazy`, `@NSCopying`, and `willSet`/`didSet`. This proposal aims to generalize and unify these concepts such that they are implemented via the same underlying framework and can be easily extended. Clients could even implement their own behaviors. It sounds awesome. Some example behaviors include: lazy, memoization, delayed initialization, resettable, and synchronized. Definitely worth the read! ### Mailing lists -Andyy Hope started [a discussion](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/003819.html) around adding an `.allValues` static variable to enums, which would return an array of all cases in the enum. Looks like there is a lot of support for the idea so far. [Jacob Bandes-Storch](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001233.html) also brought up this idea up a couple of weeks ago. I would definitely be in favor of this, as I've found myself writing this boilerplate multiple times. šŸ‘ +Andyy Hope started [a discussion](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/003819.html) around adding an `.allValues` static variable to enums, which would return an array of all cases in the enum. Looks like there is a lot of support for the idea so far. [Jacob Bandes-Storch](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001233.html) also brought up this idea up a couple of weeks ago. I would definitely be in favor of this, as I've found myself writing this boilerplate multiple times. -Kevin Ballard [suggests](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/004223.html) a more formal "This Week In Swift" newsletter. 😁 Maybe I should go ahead and setup swiftweekly.org? +Kevin Ballard [suggests](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/004223.html) a more formal "This Week In Swift" newsletter. Maybe I should go ahead and setup swiftweekly.org? **That's it for this week!** Cheers. diff --git a/_posts/2016-01-07-open-source-swift-weekly-4.md b/_posts/2016-01-07-open-source-swift-weekly-4.md index ce4105d5..f1261132 100644 --- a/_posts/2016-01-07-open-source-swift-weekly-4.md +++ b/_posts/2016-01-07-open-source-swift-weekly-4.md @@ -15,9 +15,9 @@ Now that the holidays are over, things have started to pick up again on Swift.or [Austin Zheng](https://github.com/austinzheng) submitted a [pull request](https://github.com/apple/swift/pull/838) to remove to old mirror API. -[Andrew Naylor](https://github.com/argon) merged [changes](https://github.com/apple/swift-corelibs-foundation/pull/181) to speed up JSON parsing in corelibs-foundation. We all know how much the Swift community loves JSON parsing. šŸ˜‰ +[Andrew Naylor](https://github.com/argon) merged [changes](https://github.com/apple/swift-corelibs-foundation/pull/181) to speed up JSON parsing in corelibs-foundation. We all know how much the Swift community loves JSON parsing. -[Keith Smiley](https://github.com/keith) submitted a [pull request](https://github.com/apple/swift-corelibs-xctest/pull/25) to that adds support for the Swift package manager to corelibs-xctest. šŸ‘ +[Keith Smiley](https://github.com/keith) submitted a [pull request](https://github.com/apple/swift-corelibs-xctest/pull/25) to that adds support for the Swift package manager to corelibs-xctest. Chris Lattner completely [redesigned](https://github.com/apple/swift/commit/7daaa22d936393f37176ba03975a0eec7277e1fb) the AST representation of parameters. @@ -31,6 +31,6 @@ Doug Gregor has submitted a [proposal](https://github.com/DougGregor/swift-evolu ### Mailing lists -Doug Gregor [notes](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005312.html) some surprising behavior when extending an `@objc` protocol — the members of the `extension` are not exposed to the Objective-C runtime. 😳 Luckily, I haven't run into this bug myself. +Doug Gregor [notes](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005312.html) some surprising behavior when extending an `@objc` protocol — the members of the `extension` are not exposed to the Objective-C runtime. Luckily, I haven't run into this bug myself. Finally, is `?.` the ["call-me-maybe" operator](https://twitter.com/uint_min/status/683532142677114880) in Swift? **That's it for this week!** diff --git a/_posts/2016-01-14-new-weekly-brief.md b/_posts/2016-01-14-new-weekly-brief.md index c6f5591c..274aebbb 100644 --- a/_posts/2016-01-14-new-weekly-brief.md +++ b/_posts/2016-01-14-new-weekly-brief.md @@ -7,7 +7,7 @@ title: The new weekly brief subtitle: The Swift Weekly Brief gets a new home --- -In case you are [late to the party](https://twitter.com/jesse_squires/status/687457899992383488), I finally found some time to give the *Swift Weekly Brief* a proper home. Starting this newsletter kind of happened by accident when I [first wrote](/swift-open-source/) about the Swift open source announcement. Since then, it was kind of bootstrapped here on my personal blog and started to feel awkward. I hacked together [the new site](http://swiftweekly.github.io) in a couple of nights and moved all the previous posts over. Today's [issue #5](http://swiftweekly.github.io/issue-5/) is the first one to be originally published at [swiftweekly.github.io](http://swiftweekly.github.io). However, there is more here than just organization and a nice separation of concerns. +In case you are [late to the party](https://twitter.com/jesse_squires/status/687457899992383488), I finally found some time to give the *Swift Weekly Brief* a proper home. Starting this newsletter kind of happened by accident when I [first wrote]({{ site.url }}{% post_url 2015-12-06-swift-open-source %}) about the Swift open source announcement. Since then, it was kind of bootstrapped here on my personal blog and started to feel awkward. I hacked together [the new site](http://swiftweekly.github.io) in a couple of nights and moved all the previous posts over. Today's [issue #5](http://swiftweekly.github.io/issue-5/) is the first one to be originally published at [swiftweekly.github.io](http://swiftweekly.github.io). However, there is more here than just organization and a nice separation of concerns. diff --git a/_posts/2016-02-06-jsqmessages-call-for-contributors.md b/_posts/2016-02-06-jsqmessages-call-for-contributors.md index 5c121ba3..4cabb3e1 100644 --- a/_posts/2016-02-06-jsqmessages-call-for-contributors.md +++ b/_posts/2016-02-06-jsqmessages-call-for-contributors.md @@ -7,7 +7,7 @@ title: Call for contributors subtitle: Join the JSQMessagesViewController team! --- -Do you love writing code? Are you passionate about open source? Do you want to get more involved, but have yet to find a project to which you want contribute? Are you interested in contributing to a widely used, impactful project? Then I have a proposition for you! šŸ˜„ I am looking for dedicated core contributors to help maintain [JSQMessagesViewController](https://github.com/jessesquires/JSQMessagesViewController)! +Do you love writing code? Are you passionate about open source? Do you want to get more involved, but have yet to find a project to which you want contribute? Are you interested in contributing to a widely used, impactful project? Then I have a proposition for you! I am looking for dedicated core contributors to help maintain [JSQMessagesViewController](https://github.com/jessesquires/JSQMessagesViewController)! @@ -19,7 +19,7 @@ Don't worry — I still plan to play a large role in the development of the ### Impact -Contributing to open source is extremely rewarding and provides you with an opportunity to **give back**. If you are reading this, it is nearly impossible for you to not have benefited from open source in *some way*. You might even use JSQMessages. šŸ˜„ Working on this library will give you a chance to work on a high profile, high impact project for the iOS community. Not to mention, you will learn a lot! And it will be fun! šŸ¤“ +Contributing to open source is extremely rewarding and provides you with an opportunity to **give back**. If you are reading this, it is nearly impossible for you to not have benefited from open source in *some way*. You might even use JSQMessages. Working on this library will give you a chance to work on a high profile, high impact project for the iOS community. Not to mention, you will learn a lot! And it will be fun! If you aren't convinced, here's some data to help! diff --git a/_posts/2016-02-19-swifty-presenters.md b/_posts/2016-02-19-swifty-presenters.md index a53b2b14..31887bd6 100644 --- a/_posts/2016-02-19-swifty-presenters.md +++ b/_posts/2016-02-19-swifty-presenters.md @@ -19,16 +19,16 @@ A few weeks ago, I spoke at [Realm](https://realm.io) in San Francisco at the Sw ### Thoughts -Realm's [transcript](https://realm.io/news/slug-jesse-squires-swifty-view-controller-presenters/) of the talk is excellent. They always do such an amazing job with these posts! šŸ™Œ +Realm's [transcript](https://realm.io/news/slug-jesse-squires-swifty-view-controller-presenters/) of the talk is excellent. They always do such an amazing job with these posts! 🙌 This talk examines the `UIPresentationController` API that was introduced in iOS 8 and explores ideas for making it more *swifty*. It isn't too technical, but these APIs are really interesting to me and can be really powerful. However, I feel like they are often overlooked. (Maybe this is because a lot of developers are still supporting iOS 7?) Where developers could utilize these APIs, they instead opt for view controller containment — which is often more cumbersome. I'm formalizing these ideas from the talk (and possibly more!) in a new framework — [PresenterKit](https://github.com/jessesquires/PresenterKit). It is not quite finished, but when it is I will push it to [CocoaPods](https://cocoapods.org). Meanwhile, feel free to check it out. There is also an [example project](https://github.com/jessesquires/PresenterKit/tree/develop/Example), which includes all the code from the talk. -Overall, I think the talk was really well received. If you have any feedback, I would love to hear it. [Let me know!](https://twitter.com/jesse_squires) šŸ˜„ +Overall, I think the talk was really well received. If you have any feedback, I would love to hear it. [Let me know!](https://twitter.com/jesse_squires) 😀 ### Abstract ->One major shortcoming of UIKit is that view controllers have too many responsibilities. This talk focuses on one — presenting and dismissing view controllers — and how we can re-examine and redefine these common operations with a more Swifty API that reduces boilerplate and increases expressivity. +> One major shortcoming of UIKit is that view controllers have too many responsibilities. This talk focuses on one — presenting and dismissing view controllers — and how we can re-examine and redefine these common operations with a more Swifty API that reduces boilerplate and increases expressivity. {% include post_image.html %} diff --git a/_posts/2016-03-21-contributing-to-swift.md b/_posts/2016-03-21-contributing-to-swift.md index 25062640..872de1b4 100644 --- a/_posts/2016-03-21-contributing-to-swift.md +++ b/_posts/2016-03-21-contributing-to-swift.md @@ -13,17 +13,17 @@ image: half_width: false --- -Earlier this month I had the incredible opportunity to speak at the [try! Swift conference](http://www.tryswiftconf.com/en) in Tokyo, Japan. šŸ‡ÆšŸ‡µ It was such a fun and rewarding experience. A [video of the talk](https://realm.io/news/tryswift-jesse-squires-contributing-open-source-swift/) is now online over at [Realm's](https://realm.io) blog, where it is synced with my [slides](https://speakerdeck.com/jessesquires/contributing-to-open-source-swift). If you have not already seen it, go check it out! +Earlier this month I had the incredible opportunity to speak at the [try! Swift conference](https://www.tryswift.co) in Tokyo, Japan. šŸ‡ÆšŸ‡µ It was such a fun and rewarding experience. A [video of the talk](https://realm.io/news/tryswift-jesse-squires-contributing-open-source-swift/) is now online over at [Realm's](https://realm.io) blog, where it is synced with my [slides](https://speakerdeck.com/jessesquires/contributing-to-open-source-swift). If you have not already seen it, go check it out! ### Live translation -One of the most interesting aspects of the conference was that there was live translation between English and Japanese. Most talks were in given in English, but there were at least a couple of talks given in Japanese each day — even some non-native speakers presented in Japanese! šŸ˜Ž The speakers met with the translation team multiple times to review our slide decks before presenting to ensure top quality. Then attendees were given receivers with earphones, and the translators sat in the back in a cubicle listening and translating. We also had Q&A sessions with speakers and attendees where the translators helped bridge the language barrier. It was awesome. šŸŽ‰ +One of the most interesting aspects of the conference was that there was live translation between English and Japanese. Most talks were in given in English, but there were at least a couple of talks given in Japanese each day — even some non-native speakers presented in Japanese! 😎 The speakers met with the translation team multiple times to review our slide decks before presenting to ensure top quality. Then attendees were given receivers with earphones, and the translators sat in the back in a cubicle listening and translating. We also had Q&A sessions with speakers and attendees where the translators helped bridge the language barrier. It was awesome. 🎉 -Because of this, you will notice that I'm speaking somewhat slowly during the presentation and pausing often. And so for me personally, it feels a bit awkward when I watch this. Nonetheless, I think the talk was really well received. If you have any feedback, I would love to hear it. [Let me know!](https://twitter.com/jesse_squires) šŸ˜„ +Because of this, you will notice that I'm speaking somewhat slowly during the presentation and pausing often. And so for me personally, it feels a bit awkward when I watch this. Nonetheless, I think the talk was really well received. If you have any feedback, I would love to hear it. [Let me know!](https://twitter.com/jesse_squires) 😄 -Also, one part of preparing for the live translation was providing a rough transcript before the conference. You can find all of my talk materials [on GitHub](https://github.com/jessesquires/talks). And as always, Realm's [transcript](https://realm.io/news/tryswift-jesse-squires-contributing-open-source-swift/) of the talk is excellent. šŸ™Œ +Also, one part of preparing for the live translation was providing a rough transcript before the conference. You can find all of my talk materials [on GitHub](https://github.com/jessesquires/talks). And as always, Realm's [transcript](https://realm.io/news/tryswift-jesse-squires-contributing-open-source-swift/) of the talk is excellent. 🙌 ### Thoughts diff --git a/_posts/2016-05-20-swift-documentation.md b/_posts/2016-05-20-swift-documentation.md index 1cfa490b..8030ebcc 100644 --- a/_posts/2016-05-20-swift-documentation.md +++ b/_posts/2016-05-20-swift-documentation.md @@ -14,7 +14,7 @@ image: half_width: false --- -The Swift community is ecstatic about Swift. There are so many new libraries being released each week that some have created [package indexes](https://swiftmodules.com) — even [IBM](https://developer.ibm.com/swift/products/package-catalog/). But of course, a library is only as great as its documentation. +The Swift community is ecstatic about Swift. There are so many new libraries being released each week that some have created [package indexes](https://swiftpackageindex.com) — even [IBM](https://developer.ibm.com/languages/swift/category/package-catalog/). But of course, a library is only as great as its documentation. @@ -40,7 +40,7 @@ Writing clear, understandable documentation is not easy to learn and it's more d Here's an example from [JSQMessagesViewController](http://cocoadocs.org/docsets/JSQMessagesViewController/7.2.0/Protocols/JSQMessagesCollectionViewDataSource.html#//api/name/collectionView:messageDataForItemAtIndexPath:). It's not Swift, but it illustrates these ideas. -{% highlight objc %} +```objc /** * Asks the data source for the message data that corresponds to the specified item at indexPath in the collectionView. * @@ -50,11 +50,11 @@ Here's an example from [JSQMessagesViewController](http://cocoadocs.org/docsets/ * @return An initialized object that conforms to the `JSQMessageData` protocol. You must not return `nil` from this method. */ - (id)collectionView:(JSQMessagesCollectionView *)collectionView messageDataForItemAtIndexPath:(NSIndexPath *)indexPath; -{% endhighlight %} +``` This reads very similarly to the `UICollectionViewDataSource` method `- collectionView: cellForItemAtIndexPath:`. It follows the precedent set by UIKit, not only in terms of the API design but also the documentation. Doing this allows your library to feel natural and familiar to users. -After enough imitation, you'll eventually find your own voice and get enough experience that you won't need to reference others' documentation in order to write your own. Writing documentation will begin to flow naturally. It might even be fun! šŸ˜‰ +After enough imitation, you'll eventually find your own voice and get enough experience that you won't need to reference others' documentation in order to write your own. Writing documentation will begin to flow naturally. It might even be fun! 😉 Also, strive to provide [100% coverage](https://twitter.com/orta/status/471009574276050944). This is relatively easy to do. It's much easier than having 100% test coverage, for example. It's something to be proud of, and it will make you and your library feel complete. @@ -68,7 +68,7 @@ By far, the best way to generate docs for Swift (and Objective-C!) libraries is Once installed, just run `jazzy` from the command line with a few configuration parameters and you'll have beautifully generated docs in seconds. The [README](https://github.com/realm/jazzy/blob/master/README.md) has all of the details, but here's an example from [PresenterKit](https://github.com/jessesquires/PresenterKit): -{% highlight bash %} +```bash jazzy --swift-version 2.2 -o ./ \ --source-directory PresenterKit/ \ --readme PresenterKit/README.md \ @@ -76,7 +76,7 @@ jazzy --swift-version 2.2 -o ./ \ -u 'https://twitter.com/jesse_squires' \ -m 'PresenterKit' \ -g 'https://github.com/jessesquires/PresenterKit' -{% endhighlight %} +``` You need to specify a version of Swift, tell jazzy where your source code is, and provide some basic author information. It couldn't be easier. Run `jazzy --help` to see all of the possible usage options. @@ -116,9 +116,9 @@ This is where it all comes together. On the *gh-pages* branch, I add the *develo On the [gh-pages](https://github.com/jessesquires/JSQCoreDataKit/tree/gh-pages) branch of [JSQCoreDataKit](https://github.com/jessesquires/JSQCoreDataKit), you'll find two small bash scripts. -The first is [build_docs.sh](https://github.com/jessesquires/JSQCoreDataKit/blob/gh-pages/build_docs.sh), which will update the submodule and build the docs. These can then be previewed in Safari by opening `index.html`. +The first is [build_docs.sh](https://github.com/jessesquires/JSQCoreDataKit/blob/develop/scripts/build_docs.zsh), which will update the submodule and build the docs. These can then be previewed in Safari by opening `index.html`. -{% highlight bash %} +```bash git submodule update --remote jazzy --swift-version 2.2 -o ./ \ @@ -128,23 +128,23 @@ jazzy --swift-version 2.2 -o ./ \ -u 'https://twitter.com/jesse_squires' \ -m 'JSQCoreDataKit' \ -g 'https://github.com/jessesquires/JSQCoreDataKit' -{% endhighlight %} +``` The second is [publish_docs.sh](https://github.com/jessesquires/JSQCoreDataKit/blob/gh-pages/publish_docs.sh) which will first call the build script, then push the docs to GitHub. -{% highlight bash %} +```bash ./build_docs.sh git add . git commit -am "auto-update docs" git push git status -{% endhighlight %} +``` #### Workflow With all of this in place, updating the documentation for my library is painless. I write code and docs, then push to *develop*. Then I switch directories to the *gh-pages* checkout and run `./publish_docs.sh`. -{% highlight bash %} +```bash cd ~/GitHub/JSQCoreDataKit # write code and docs # commit @@ -152,7 +152,7 @@ git push cd ~/GitHub-Pages/JSQCoreDataKit ./publish_docs.sh # update docs -{% endhighlight %} +``` Right now, I prefer running the `publish_docs.sh` script manually so that the docs only update when I want them to — for corrections and major releases. However, you could easily do this in the `after_success:` step of your [Travis-CI](https://travis-ci.org) script. diff --git a/_posts/2016-05-22-open-source-everything.md b/_posts/2016-05-22-open-source-everything.md index c9d0fbb5..de162363 100644 --- a/_posts/2016-05-22-open-source-everything.md +++ b/_posts/2016-05-22-open-source-everything.md @@ -13,7 +13,7 @@ image: half_width: false --- -I recently had an incredible experience with one of my open source projects that I'd like to share. It's a story of openness and collaboration that I hope other open source project maintainers will find valuable. This post continues the theme of "building successful open source projects" from my [previous article](/swift-documentation/) on documentation. +I recently had an incredible experience with one of my open source projects that I'd like to share. It's a story of openness and collaboration that I hope other open source project maintainers will find valuable. This post continues the theme of "building successful open source projects" from my [previous article]({{ site.url }}{% post_url 2016-05-20-swift-documentation %}) on documentation. @@ -32,7 +32,7 @@ The success of this release was the result of a number of attributes about this 1. It has [100% API documentation](https://jessesquires.github.io/JSQCoreDataKit/) 2. It has [96% test coverage](https://codecov.io/gh/jessesquires/JSQCoreDataKit) 3. It has [continuous integration](https://travis-ci.org/jessesquires/JSQCoreDataKit) with Travis CI -4. [All issues](https://github.com/jessesquires/JSQCoreDataKit/issues?utf8=āœ“&q=is%3Aissue) are organized, labeled, and clearly explained +4. [All issues](https://github.com/jessesquires/JSQCoreDataKit/issues?q=is%3Aissue) are organized, labeled, and clearly explained 5. Each release has a corresponding [milestone](https://github.com/jessesquires/JSQCoreDataKit/milestones?state=closed) that groups the issues going into it Collectively, *all* of these things serve as *documentation* — not just the API documentation itself. By keeping a project organized in this fashion, you can empower *anyone* to easily and successfully contribute. diff --git a/_posts/2016-06-04-avoiding-objc-in-swift.md b/_posts/2016-06-04-avoiding-objc-in-swift.md index 11be951a..297b35ce 100644 --- a/_posts/2016-06-04-avoiding-objc-in-swift.md +++ b/_posts/2016-06-04-avoiding-objc-in-swift.md @@ -17,7 +17,7 @@ For the purposes of this post, I've simplified the code from the project I'm wor Suppose we have a group of view controllers that all need a view model and a "cancel" button. Each controller needs to be able to execute its own code when "cancel" is tapped. We may write something like this: -{% highlight swift %} +```swift struct ViewModel { let title: String } @@ -27,11 +27,11 @@ protocol ViewControllerType: class { func didTapCancelButton(sender: UIBarButtonItem) } -{% endhighlight %} +``` If we stopped here, then each controller would have to add and wire up its own cancel button. That ends up being a lot of boilerplate. We can fix that with an extension (using the old `Selector("")` syntax): -{% highlight swift %} +```swift extension ViewControllerType where Self: UIViewController { func configureNavigationItem() { navigationItem.leftBarButtonItem = UIBarButtonItem( @@ -40,11 +40,11 @@ extension ViewControllerType where Self: UIViewController { action: Selector("didTapCancelButton:")) } } -{% endhighlight %} +``` Now each controller that conforms to this protocol can call `configureNavigationItem()` from `viewDidLoad()`, which is much better. Our controller might look like this: -{% highlight swift %} +```swift class MyViewController: UIViewController, ViewControllerType { var viewModel = ViewModel(title: "Title") @@ -57,14 +57,14 @@ class MyViewController: UIViewController, ViewControllerType { // handle tap } } -{% endhighlight %} +``` This is rather simple, but you can imagine more complex configurations that we could apply using this strategy. After updating the snippet above for Swift 2.2, we have the following: -{% highlight swift %} +```swift extension ViewControllerType where Self: UIViewController { func configureNavigationItem() { navigationItem.leftBarButtonItem = UIBarButtonItem( @@ -73,15 +73,15 @@ extension ViewControllerType where Self: UIViewController { action: #selector(didTapCancelButton(_:))) } } -{% endhighlight %} +``` And now we have a problem, a new compiler error. -{% highlight bash %} +```bash Argument of '#selector' refers to a method that is not exposed to Objective-C. Fix-it Add '@objc' to expose this method to Objective-C -{% endhighlight %} +``` ### When `@objc` tries to ruin everything @@ -105,7 +105,7 @@ We can decompose this protocol by separating out all of the `@objc` code into it First we split up the protocol into two protocols, `ViewModelConfigurable` and `NavigationItemConfigurable`. Our previous extension on `ViewControllerType` can move to `NavigationItemConfigurable` instead. -{% highlight swift %} +```swift protocol ViewModelConfigurable { var viewModel: ViewModel { get set } } @@ -122,13 +122,13 @@ extension NavigationItemConfigurable where Self: UIViewController { action: #selector(didTapCancelButton(_:))) } } -{% endhighlight %} +``` Finally, we can define our original `ViewControllerType` protocol as a `typealias`. -{% highlight swift %} +```swift typealias ViewControllerType = ViewModelConfigurable & NavigationItemConfigurable -{% endhighlight %} +``` Now everything works exactly as it did before migrating to Swift 2.2 and our original view controller definition above does not have to change. Nothing is ruined. If you ever face a similar situation, or if you generally want to contain the use of `@objc` (*which you should*), then I highly recommend adopting this strategy. diff --git a/_posts/2016-07-25-migrating-to-swift-3.md b/_posts/2016-07-25-migrating-to-swift-3.md index 71b0965a..8721620a 100644 --- a/_posts/2016-07-25-migrating-to-swift-3.md +++ b/_posts/2016-07-25-migrating-to-swift-3.md @@ -29,24 +29,24 @@ Here's my basic git workflow for migrating my open source libraries: This creates the following model: -{% highlight bash %} +```bash o-----o develop (swift 2.2) \ o-----o swift2.3 \ o-----o swift3.0 -{% endhighlight %} +``` My plan for now is to keep these branches in sync like what you see above. That is, `swift2.3` will be ahead of `develop` and `swift3.0` will be ahead of `swift2.3`. The end goal will be to merge changes from each branch back into a single squashed commit on `develop` when the final release of Xcode 8 is out. -{% highlight bash %} +```bash merge 2.3 merge 3.0 o------o o o-----------o develop \ / / o--- swift2.3 ---o / \ / o--- swift3.0 ---o -{% endhighlight %} +``` Each merge into `develop` will be a major release of the library. For example, if the library is currently at `v2.0`, then the Swift 2.3 merge will result in `v3.0` of the library and the Swift 3.0 merge will result in `v4.0` of the library. This ensures [semantic versioning](http://semver.org) and allows clients to safely migrate between versions *at their own pace* as they adopt the next version of Swift. @@ -58,9 +58,9 @@ So far, the only dependencies I have for this project are my own libraries, whic Until Xcode 8 is final, you'll need to point your pods to these new branches: -{% highlight ruby %} +```ruby pod 'MyLibrary', :git => 'https://github.com/username/MyLibrary.git', :branch => 'swift3.0' -{% endhighlight %} +``` This tells CocoaPods to fetch the latest on the `swift3.0` branch, instead of the latest published version. diff --git a/_posts/2016-07-31-enums-as-configs.md b/_posts/2016-07-31-enums-as-configs.md index 3b5fbb8d..748c81e0 100644 --- a/_posts/2016-07-31-enums-as-configs.md +++ b/_posts/2016-07-31-enums-as-configs.md @@ -23,7 +23,7 @@ Let's use a simple, familiar example — a [`UITableViewCell`](https://devel Given the problem above, we may design something like the following: -{% highlight swift %} +```swift enum CellStyle { case login case profile @@ -79,7 +79,7 @@ class SettingsViewController: UITableViewController { // ... } -{% endhighlight %} +``` We create our usual `UITableViewCell` and [`UITableViewController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewController_Class/) subclasses, and define a style `enum`. Within each view controller we set the appropriate style when we create and configure the cell. Easy enough, right? @@ -99,7 +99,7 @@ This approach is fragile, [imperative](https://en.wikipedia.org/wiki/Imperative_ Rather than obfuscate what's happening by exposing merely an `enum`, we can open up our API using a technique known as [inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control). Continuing with our example, what if we create an entirely new model to represent our cell style? Consider the following: -{% highlight swift %} +```swift struct CellStyle { let labelColor: UIColor let labelFont: UIFont @@ -123,7 +123,7 @@ class CommonTableCell: UITableViewCell { // ... } -{% endhighlight %} +``` Instead of an `enum`, we can create a `struct` that represents our cell style. Not only does this clearly define all attributes of the style, but we can now **map this value directly onto** the cell in a less procedural, more [declarative](https://en.wikipedia.org/wiki/Declarative_programming) way. In other scenarios, we could pass a configuration to a class's designated initializer. @@ -135,7 +135,7 @@ Another reason this design is superior is because it allows us to provide sensib In Swift, we can provide default values in the initializer: -{% highlight swift %} +```swift struct CellStyle { let labelColor: UIColor let labelFont: UIFont @@ -155,11 +155,11 @@ struct CellStyle { self.accessory = accessory } } -{% endhighlight %} +``` And for our library-provided styles that we previously defined using an `enum`, we can define properties in an extension: -{% highlight swift %} +```swift extension CellStyle { static var settings: CellStyle { return CellStyle(labelColor: .purple(), @@ -172,13 +172,13 @@ extension CellStyle { // usage: cell.apply(style: .settings) -{% endhighlight %} +``` Notice the call site can actually remain *unchanged* due to Swift's type inference. Previously `.settings` referred to the `enum` value, but it now refers to the `static var` property in the extension. We can provide a more modular, extensible API without sacrificing conciseness or clarity. As mentioned above, clients can now effortlessly provide their own styles by adding an extension. Even more, they can choose to only override some of the default properties: -{% highlight swift %} +```swift extension CellStyle { static var custom: CellStyle { // uses default fonts @@ -187,7 +187,7 @@ extension CellStyle { accessory: UIImage(named: "action")!) } } -{% endhighlight %} +``` ### Configurations as behaviors @@ -199,9 +199,9 @@ A savvy reader would likely realize by now that this is exactly how the [`URLSes Let's look at another example on the other side of the spectrum — [`UIPresentationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPresentationController_class/). This API allows us to provide custom presentations for view controllers by creating custom presentation controllers. Previously, this API was limited to... an `enum`! The only presentation styles available were those defined by [`UIModalPresentationStyle`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/swift/enum/c:@E@UIModalPresentationStyle). As we've explored above, this incredibly inflexible for clients. However, `UIKit` unfortunately did not get this new API 100% correct. There are parts of the public API that still depend on `UIModalPresentationStyle` values: -{% highlight swift %} +```swift func adaptivePresentationStyle(for traitCollection: UITraitCollection) -> UIModalPresentationStyle -{% endhighlight %} +``` This method requires you to return a `UIModalPresentationStyle` value for the specified `UITraitCollection`. What we *should* be able to do here is return any arbitrary `UIPresentationController`. If you want to learn more, see [my talk](/swifty-presenters/) about these APIs. diff --git a/_posts/2016-09-30-speaking-at-frenchkit.md b/_posts/2016-09-30-speaking-at-frenchkit.md index 793e0cc6..38d78b1c 100644 --- a/_posts/2016-09-30-speaking-at-frenchkit.md +++ b/_posts/2016-09-30-speaking-at-frenchkit.md @@ -25,11 +25,11 @@ The slides from my talk are [on Speaker Deck](https://speakerdeck.com/jessesquir ### Highlights -I'm not sure if I could articulate this better than [Rob Napier](https://twitter.com/cocoaphony), so just [read his post](http://robnapier.net/copying), and mentally paste it here. šŸ˜„ Always, these indie conferences are about the people — and the people at FrenchKit were awesome. We do not often have the opportunity to meet people from our community face-to-face, so it's a special occasion when we do. +I'm not sure if I could articulate this better than [Rob Napier](https://twitter.com/cocoaphony), so just [read his post](http://robnapier.net/copying), and mentally paste it here. 😄 Always, these indie conferences are about the people — and the people at FrenchKit were awesome. We do not often have the opportunity to meet people from our community face-to-face, so it's a special occasion when we do. -Aside from the fantastic lineup of [speakers](http://frenchkit.fr/#programme), I got to meet Bas Broek ([**@basthomas**](https://twitter.com/BasThomas)) who has been contributing to [Swift Weekly Brief](http://swiftweekly.github.io), as well as SĆ©bastien Duperron ([**@liquidseb**](https://twitter.com/liquidseb)) who contributed significantly to [JSQCoreDataKit](https://github.com/jessesquires/JSQCoreDataKit) (which I [wrote about](/open-source-everything/) before). There were many other great folks (including a few users of [JSQMessages](https://github.com/jessesquires/JSQMessagesViewController)), but definitely too many to list here. +Aside from the fantastic lineup of [speakers](http://frenchkit.fr/#programme), I got to meet Bas Broek ([**@basthomas**](https://twitter.com/BasThomas)) who has been contributing to [Swift Weekly Brief](http://swiftweekly.github.io), as well as SĆ©bastien Duperron ([**@liquidseb**](https://twitter.com/liquidseb)) who contributed significantly to [JSQCoreDataKit](https://github.com/jessesquires/JSQCoreDataKit) (which I [wrote about]({{ site.url }}{% post_url 2016-05-22-open-source-everything %}) before). There were many other great folks (including a few users of [JSQMessages](https://github.com/jessesquires/JSQMessagesViewController)), but definitely too many to list here. -The organizers opened with a mock Apple-esque keynote. It was hilarious and I hope this part was also recorded. The conference closed with šŸ§€ and šŸ· (of course) and a fun pub quiz. We had a good time with lots of laughs. +The organizers opened with a mock Apple-esque keynote. It was hilarious and I hope this part was also recorded. The conference closed with 🧀 and 🍷 (of course) and a fun pub quiz. We had a good time with lots of laughs. {% include image.html file="frenchkit-michel.jpg" diff --git a/_posts/2016-10-01-shipping-swift-3.md b/_posts/2016-10-01-shipping-swift-3.md index 3f6ba557..d75b01f8 100644 --- a/_posts/2016-10-01-shipping-swift-3.md +++ b/_posts/2016-10-01-shipping-swift-3.md @@ -7,7 +7,7 @@ title: Shipping Swift 3.0 subtitle: An update on my open source libraries --- -I'm happy to share that all of my open source Swift libraries have (finally) been updated for Swift 3. If you've been waiting for any of these final releases, you can now run `pod update` or `carthage update` and relax — sorry it took so long! I wrote about [migrating to Swift 3](/migrating-to-swift-3/) a few months ago and this post shares the final results of the process that I outlined in there. +I'm happy to share that all of my open source Swift libraries have (finally) been updated for Swift 3. If you've been waiting for any of these final releases, you can now run `pod update` or `carthage update` and relax — sorry it took so long! I wrote about [migrating to Swift 3]({{ site.url }}{% post_url 2016-07-25-migrating-to-swift-3 %}) a few months ago and this post shares the final results of the process that I outlined in there. @@ -23,7 +23,7 @@ This will allow you to update these libraries on your own time, without forcing - [JSQWebViewController](https://github.com/jessesquires/JSQWebViewController/releases) - [DefaultStringConvertible](https://github.com/jessesquires/DefaultStringConvertible/releases) (Note: this library was not updated to Swift 2.3, only Swift 3.0) -Updating so many libraries is time consuming, but the branching model outlined in [my previous post](/migrating-to-swift-3/) made it simple. Here's the final git flow: +Updating so many libraries is time consuming, but the branching model outlined in [my previous post]({{ site.url }}{% post_url 2016-07-25-migrating-to-swift-3 %}) made it simple. Here's the final git flow: 1. The `swift2.3` branch is finished and ready 2. Squash and merge `swift2.3` into `develop` @@ -37,18 +37,18 @@ Updating so many libraries is time consuming, but the branching model outlined i If the library was initially at version 2.0, here's the gist of what this looks like: -{% highlight bash %} +```bash v2 (Swift 2.2) v3 (Swift 2.3) v4 (Swift 3.0) o------o--------------------o--------------------o--------------> develop/master \ / / o--- swift2.3 ---o / \ / o--- swift3.0 ---o -{% endhighlight %} +``` ### Deprecations -Also note that a few of my libraries have been deprecated, which I wrote about [here](/swift-3-sherlocked-my-libraries/). These libraries were no longer valuable in general, or no longer needed in Swift 3. +Also note that a few of my libraries have been deprecated, which I wrote about [here]({{ site.url }}{% post_url 2016-07-03-swift-3-sherlocked-my-libraries %}). These libraries were no longer valuable in general, or no longer needed in Swift 3. - [GrandSugarDispatch](https://github.com/jessesquires/GrandSugarDispatch) - [JSQNotificationObserverKit](https://github.com/jessesquires/JSQNotificationObserverKit) diff --git a/_posts/2016-10-03-understanding-swift-evolution.md b/_posts/2016-10-03-understanding-swift-evolution.md index 933b0bef..1fcf27e3 100644 --- a/_posts/2016-10-03-understanding-swift-evolution.md +++ b/_posts/2016-10-03-understanding-swift-evolution.md @@ -7,7 +7,7 @@ title: Understanding Swift Evolution subtitle: What can we learn by analyzing the proposals? --- -I recently [spoke at the FrenchKit conference](/speaking-at-frenchkit/) about [Swift Evolution](https://github.com/apple/swift-evolution). The [talk](https://speakerdeck.com/jessesquires/140-proposals-in-30-minutes), *140 proposals in 30 minutes*, was originally intended to be an overview of the process and each of the proposals. However, as I was writing the talk, it evolved into something much more interesting. I ended up writing some code to analyze the proposals instead. +I recently [spoke at the FrenchKit conference]({{ site.url }}{% post_url 2016-09-30-speaking-at-frenchkit %}) about [Swift Evolution](https://github.com/apple/swift-evolution). The [talk](https://speakerdeck.com/jessesquires/140-proposals-in-30-minutes), *140 proposals in 30 minutes*, was originally intended to be an overview of the process and each of the proposals. However, as I was writing the talk, it evolved into something much more interesting. I ended up writing some code to analyze the proposals instead. @@ -30,7 +30,7 @@ The [swift-proposal-analyzer](https://github.com/jessesquires/swift-proposal-ana In the playground, you are presented with an array of `Proposal` objects, which contain most of the proposal metadata, as well as the raw file contents. -{% highlight swift %} +```swift final class Proposal { @@ -45,23 +45,23 @@ final class Proposal { let wordCount: Int } -{% endhighlight %} +``` A `Proposal` has a title and SE number, an array of `Author` objects (1 or more), a `Status`, a filename, the file contents, and the total (rough) word count. For now, `Author` only contains the author's name. -{% highlight swift %} +```swift struct Author { let name: String } -{% endhighlight %} +``` The `Status` of a proposal is defined as an `enum`: -{% highlight swift %} +```swift enum Status { case inReview @@ -73,7 +73,7 @@ enum Status { case withdrawn } -{% endhighlight %} +``` We've gone from a directory of plain text files to structured data that we can query and filter. šŸ˜Ž @@ -81,28 +81,28 @@ We've gone from a directory of plain text files to structured data that we can q Here are a few brief examples to show what kinds of questions we can ask and answer. -{% highlight swift %} +```swift // Find proposals implemented in Swift 3.0 let implementedInSwift3: [Proposal] = analyzer.proposalsWith(status: .implemented(.v3_0)) -{% endhighlight %} +``` -{% highlight swift %} +```swift // Find proposals authored or co-authored by Chris Lattner let proposalsByLattner: [Proposal] = analyzer.proposals.filter { p -> Bool in p.writtenBy("Chris Lattner") } -{% endhighlight %} +``` -{% highlight swift %} +```swift // Find total mentions of "Objective-C" across all proposals let count: Int = analyzer.occurrences(of: "Objective-C") -{% endhighlight %} +``` ### Querying the data diff --git a/_posts/2016-11-05-140-proposals-frenchkit-video.md b/_posts/2016-11-05-140-proposals-frenchkit-video.md index 93e417ce..12847b62 100644 --- a/_posts/2016-11-05-140-proposals-frenchkit-video.md +++ b/_posts/2016-11-05-140-proposals-frenchkit-video.md @@ -13,13 +13,13 @@ image: half_width: false --- -As you may know, I [spoke at FrenchKit](/speaking-at-frenchkit/) a couple of months ago. The organizers have been working hard to get all of [the videos](http://frenchkit.fr/#videos) edited and uploaded, and my talk is [now available here](https://www.youtube.com/watch?v=0sYQAtoK3VQ). šŸ˜„ +As you may know, I [spoke at FrenchKit]({{ site.url }}{% post_url 2016-09-30-speaking-at-frenchkit %}) a couple of months ago. The organizers have been working hard to get all of [the videos](http://frenchkit.fr/#videos) edited and uploaded, and my talk is [now available here](https://www.youtube.com/watch?v=0sYQAtoK3VQ). šŸ˜„ ### Slides and code -As usual, you can find my slides [on Speaker Deck](https://speakerdeck.com/jessesquires/140-proposals-in-30-minutes) and the code [on GitHub](https://github.com/jessesquires/swift-proposal-analyzer). A few weeks ago I also wrote a post, [*Understanding Swift Evolution*](/understanding-swift-evolution/), that explains the project and results in more detail. +As usual, you can find my slides [on Speaker Deck](https://speakerdeck.com/jessesquires/140-proposals-in-30-minutes) and the code [on GitHub](https://github.com/jessesquires/swift-proposal-analyzer). A few weeks ago I also wrote a post, [*Understanding Swift Evolution*]({{ site.url }}{% post_url 2016-10-03-understanding-swift-evolution %}), that explains the project and results in more detail. ### Abstract diff --git a/_posts/2017-01-08-swift-documentation-part-2.md b/_posts/2017-01-08-swift-documentation-part-2.md index 21935271..4d26af41 100644 --- a/_posts/2017-01-08-swift-documentation-part-2.md +++ b/_posts/2017-01-08-swift-documentation-part-2.md @@ -15,7 +15,7 @@ I previously wrote about [writing great documentation in Swift](/swift-documenta As I mentioned before, you'll want to use Realm's [jazzy](https://github.com/realm/jazzy) — *Soulful docs for Swift and Objective-C*. Here's an example of the docs script that I use for [PresenterKit](https://github.com/jessesquires/PresenterKit): -{% highlight bash %} +```bash jazzy \ --clean \ --author 'Jesse Squires' \ @@ -26,7 +26,8 @@ jazzy \ --readme 'README.md' \ --documentation 'Guides/*.md' \ --output docs/ \ -{% endhighlight %} + +``` You need to tell jazzy where your source code is and provide some basic author information. It couldn't be easier. Run `jazzy --help` to see all of the possible usage options. @@ -38,4 +39,4 @@ In the previous post, publishing docs with GitHub was a somewhat clunky process ### Complete workflow -Once you've made changes to your code and header docs, run [your script](https://github.com/jessesquires/PresenterKit/blob/develop/build_docs.sh) to generate the documentation which should dump everything into `docs/`. Then simply commit your changes and push to GitHub, where your documentation will be [rendered automatically](https://jessesquires.github.io/JSQCoreDataKit/). +Once you've made changes to your code and header docs, run [your script](https://github.com/jessesquires/PresenterKit/blob/develop/scripts/build_docs.zsh) to generate the documentation which should dump everything into `docs/`. Then simply commit your changes and push to GitHub, where your documentation will be [rendered automatically](https://jessesquires.github.io/JSQCoreDataKit/). diff --git a/_posts/2017-01-16-testing-without-ocmock.md b/_posts/2017-01-16-testing-without-ocmock.md index 71f13cf0..959f5ee6 100644 --- a/_posts/2017-01-16-testing-without-ocmock.md +++ b/_posts/2017-01-16-testing-without-ocmock.md @@ -7,7 +7,7 @@ title: Testing and mocking without OCMock subtitle: For Swift and Objective-C --- -[OCMock](http://ocmock.org) is a powerful [mock object](https://en.wikipedia.org/wiki/Mock_object) unit testing library for Objective-C. Even if you are using Swift, as long as your classes inherit from `NSObject`, you can use [some of its features](http://ocmock.org/swift/). But what if you are writing pure Swift code which does not have access to the dynamic Objective-C runtime? Or, what if you don't want your Swift code to be [hampered](/avoiding-objc-in-swift/) by `NSObject` subclasses and `@objc` annotations? Perhaps, you merely want to avoid dependencies and use 'plain old' `XCTest` with Objective-C. It's relatively easy and lightweight to achieve the same effect in some testing scenarios *without* using `OCMock`. +[OCMock](http://ocmock.org) is a powerful [mock object](https://en.wikipedia.org/wiki/Mock_object) unit testing library for Objective-C. Even if you are using Swift, as long as your classes inherit from `NSObject`, you can use [some of its features](http://ocmock.org/swift/). But what if you are writing pure Swift code which does not have access to the dynamic Objective-C runtime? Or, what if you don't want your Swift code to be [hampered]({{ site.url }}{% post_url 2016-06-04-avoiding-objc-in-swift %}) by `NSObject` subclasses and `@objc` annotations? Perhaps, you merely want to avoid dependencies and use 'plain old' `XCTest` with Objective-C. It's relatively easy and lightweight to achieve the same effect in some testing scenarios *without* using `OCMock`. @@ -32,7 +32,7 @@ The most common — and highly suitable — uses for mocking are for net Suppose we have a view controller that displays a "Yes/No" prompt to the user. After the user selects an option, we need to notify another class of the action taken. This class will perform some operations and then update the UI. We want to test that when an option is tapped that the correct delegate method is called. -{% highlight swift %} +```swift protocol ControllerProtocol: class { func controllerDidSelectYes(_ controller: Controller) -> Void func controllerDidSelectNo(_ controller: Controller) -> Void @@ -49,22 +49,22 @@ class Controller: UIViewController { delegate?.controllerDidSelectNo(self) } } -{% endhighlight %} +``` We could mock `ControllerProtocol` with OCMock in an Objective-C test: -{% highlight objc %} +```objc #import - (void)test { id mockProtocol = [OCMockObject niceMockForProtocol:@protocol(ControllerProtocol)]; // write test... } -{% endhighlight %} +``` But we want to write our tests in Swift, and it would be nice to avoid another dependency. Let's use `XCTestExpectation`. In our test, we can create a class that conforms to `ControllerProtocol` and has an `XCTestExpectation` property for each protocol method. Each protocol method implementation simply calls `fulfill()` on the appropriate expectation. -{% highlight swift %} +```swift class FakeDelegate: ControllerProtocol { var yesExpectation: XCTestExpectation? var noExpectation: XCTestExpectation? @@ -77,11 +77,11 @@ class FakeDelegate: ControllerProtocol { noExpectation!.fulfill() } } -{% endhighlight %} +``` Now we can use `FakeDelegate` in our test: -{% highlight swift %} +```swift func testDidTapYes() { let controller = Controller() @@ -99,7 +99,7 @@ func testDidTapYes() { // wait for our delegate method to be called waitForExpectations(timeout: 5, handler: nil) } -{% endhighlight %} +``` If the test fails, that means tapping this button *does not* notify the delegate. diff --git a/_posts/2017-02-10-refactoring-singletons-in-swift.md b/_posts/2017-02-10-refactoring-singletons-in-swift.md index fc81ab75..8ff82a6a 100644 --- a/_posts/2017-02-10-refactoring-singletons-in-swift.md +++ b/_posts/2017-02-10-refactoring-singletons-in-swift.md @@ -17,7 +17,7 @@ On Apple platforms, singletons are everywhere in the Cocoa and Cocoa Touch frame When you implicitly reference these — and your own — singletons, it increases the amount of effort it takes to change your code. It also makes it difficult or impossible to test your code, because there's no way to change or mock those singletons from outside of the classes in which they are used. Here's what you typically see in an iOS app: -{% highlight swift %} +```swift class MyViewController: UIViewController { override func viewDidLoad() { @@ -38,7 +38,7 @@ class MyViewController: UIViewController { } } } -{% endhighlight %} +``` This is what I mean by *implicit references* — you simply use the singleton directly in your class. We can do better. There is a lightweight, easy, and low impact way to improve this in Swift. Swift makes it elegant, too. @@ -47,7 +47,7 @@ This is what I mean by *implicit references* — you simply use the singleto In short, the answer is [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection). This principle says that you should design your classes and functions such that all inputs are explicit. If you refactor the snippet above to use dependency injection, it would look like this: -{% highlight swift %} +```swift class MyViewController: UIViewController { let userManager: CurrentUserManager @@ -79,21 +79,21 @@ class MyViewController: UIViewController { } } } -{% endhighlight %} +``` This class no longer implicitly (or explicitly) depends on any singletons. It explicitly depends on a `CurrentUserManager`, `UserDefaults`, and `URLSession` — but nothing about these dependencies indicates that they are singletons. This detail no longer matters, but the functionality remains unchanged. The view controller merely knows that instances of these objects exist. At the call site you can pass in the singletons. Again, this detail is irrelevant from the class's perspective. -{% highlight swift %} +```swift let controller = MyViewController(userManager: .shared, defaults: .standard, urlSession: .shared) present(controller, animated: true, completion: nil) -{% endhighlight %} +``` Pro tip: Swift type inference works here. Instead of writing `URLSession.shared`, you can simply write `.shared`. If you ever need to provide a *different* `userDefaults` — for example, if you need to [share data with App Groups](https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6) — then it's easy to change. In fact, you *do not* have to change any code in this class. Instead of passing in `UserDefaults.standard`, you pass in `UserDefaults(suiteName: "com.myApp")`. -Furthermore, in unit tests you can now pass in fakes or mocks of these classes. Real mocking isn't possible in Swift, but there are [workarounds](/testing-without-ocmock/). It depends on how you want to structure your code. You could use a protocol for `CurrentUserManager`, which you could then "mock" in a test. You could provide a fake suite for `UserDefaults` for testing. You could make `URLSession` optional and pass `nil` in your tests. +Furthermore, in unit tests you can now pass in fakes or mocks of these classes. Real mocking isn't possible in Swift, but there are [workarounds]({{ site.url }}{% post_url 2017-01-16-testing-without-ocmock %}). It depends on how you want to structure your code. You could use a protocol for `CurrentUserManager`, which you could then "mock" in a test. You could provide a fake suite for `UserDefaults` for testing. You could make `URLSession` optional and pass `nil` in your tests. ### Refactoring hell @@ -113,7 +113,7 @@ One of my favorite features of Swift is default parameter values. They are incre You can use the singletons as default parameters: -{% highlight swift %} +```swift class MyViewController: UIViewController { init(userManager: CurrentUserManager = .shared, defaults: UserDefaults = .standard, urlSession: URLSession = .shared) { @@ -123,15 +123,15 @@ class MyViewController: UIViewController { super.init(nibName: nil, bundle: nil) } } -{% endhighlight %} +``` Now, the initializer has not changed from the perspective of the call site. But there is a world of difference in the class itself, which is now using dependency injection and no longer referencing singletons. -{% highlight swift %} +```swift let controller = MyViewController() present(controller, animated: true, completion: nil) -{% endhighlight %} +``` What have you gained with this change? You can refactor every class to use this pattern without updating any call sites. Nothing has changed semantically, nor functionally. Yet, your classes are using dependency injection. They are merely using instances internally. You can test them as described above and maintain a flexible, modular API — all while the public interface remains unchanged. Essentially, you can continue working in your codebase as if nothing ever changed. @@ -139,13 +139,13 @@ If and when the time comes to pass in custom, non-singleton parameters you can d If needed, you can even opt-in or opt-out of any of the default values. In the following example, we provide custom `UserDefaults` but keep the default parameters for `CurrentUserManager` and `URLSession`. -{% highlight swift %} +```swift let appGroupDefaults = UserDefaults(suiteName: "com.myApp")! let controller = MyViewController(defaults: appGroupDefaults) present(controller, animated: true, completion: nil) -{% endhighlight %} +``` ### Conclusion diff --git a/_posts/2017-02-15-adapting-to-change-and-cutting-corners.md b/_posts/2017-02-15-adapting-to-change-and-cutting-corners.md index 72c26173..f58b1f36 100644 --- a/_posts/2017-02-15-adapting-to-change-and-cutting-corners.md +++ b/_posts/2017-02-15-adapting-to-change-and-cutting-corners.md @@ -7,7 +7,7 @@ title: Adapting to change subtitle: And cutting corners --- -In my [previous post](/refactoring-singletons-in-swift/) I mentioned writing *adaptive* code. That is to say, writing code that is easy to change, code that is malleable. It's like creating [adaptive user interfaces](/adaptive-user-interfaces/) but for all of your classes, modules, and other components. +In my [previous post]({{ site.url }}{% post_url 2017-02-10-refactoring-singletons-in-swift %}) I mentioned writing *adaptive* code. That is to say, writing code that is easy to change, code that is malleable. It's like creating [adaptive user interfaces]({{ site.url }}{% post_url 2014-10-01-adaptive-user-interfaces %}) but for all of your classes, modules, and other components. diff --git a/_posts/2017-06-04-writing-better-singletons-in-swift.md b/_posts/2017-06-04-writing-better-singletons-in-swift.md index e5f06155..ddf36b25 100644 --- a/_posts/2017-06-04-writing-better-singletons-in-swift.md +++ b/_posts/2017-06-04-writing-better-singletons-in-swift.md @@ -7,7 +7,7 @@ title: Writing better singletons in Swift subtitle: Avoiding common pitfalls --- -In a [previous post](/blog/refactoring-singletons-in-swift/) I discussed strategies for using singletons in a cleaner, more modular way. [Singletons](https://en.wikipedia.org/wiki/Singleton_pattern) are a fact of software development, especially in iOS. *Sometimes* the design pattern actually *is* the right tool for the job. In those situations, how we can improve the way we write our own singleton classes? +In a [previous post]({{ site.url }}{% post_url 2017-02-10-refactoring-singletons-in-swift %}) I discussed strategies for using singletons in a cleaner, more modular way. [Singletons](https://en.wikipedia.org/wiki/Singleton_pattern) are a fact of software development, especially in iOS. *Sometimes* the design pattern actually *is* the right tool for the job. In those situations, how we can improve the way we write our own singleton classes? diff --git a/_posts/2017-06-05-protocol-composition-in-swift-and-objc.md b/_posts/2017-06-05-protocol-composition-in-swift-and-objc.md index a1d75a85..7a21648c 100644 --- a/_posts/2017-06-05-protocol-composition-in-swift-and-objc.md +++ b/_posts/2017-06-05-protocol-composition-in-swift-and-objc.md @@ -17,7 +17,7 @@ Let's begin with Objective-C. Optional protocol methods were introduced in Objec Consider the following example: -{% highlight objc %} +```objc @protocol MyViewControllerDelegate - (void)didDismissController:(MyViewController *)controller; @@ -33,31 +33,31 @@ Consider the following example: @property (nonatomic, weak) id delegate; @end -{% endhighlight %} +``` Calling required methods on the `delegate` is straightforward: -{% highlight objc %} +```objc [self.delegate didDismissController:self]; -{% endhighlight %} +``` With optional methods, not only do you forgo help from the compiler, but you incur the additional runtime cost of checking `-respondsToSelector:` every time you need to message the `delegate` object. -{% highlight objc %} +```objc if ([self.delegate respondsToSelector:@selector(controller:didSelectItem:)]) { [self.delegate controller:self didSelectItem:item]; } -{% endhighlight %} +``` ### The problem with `optional` Swift addresses the safety problems above and offers a convenient `?` syntax for optional members: -{% highlight swift %} +```swift delegate?.controller?(self, didSelect: item) -{% endhighlight %} +``` -In this case, you do not have to worry about runtime crashes in Swift, but there is another problem. In Swift, `optional` is *not really* "part of the language" or "pure Swift" — the feature relies on the Objective-C runtime and **it only exists for interoperability with Objective-C**. Any protocol in Swift that contains optional members must be marked as `@objc`. I have [written before](/avoiding-objc-in-swift/) about avoiding `@objc` in your Swift code as much as possible. When `@objc` infiltrates your object graph, nearly everything must inherit from `NSObject` which means you cannot use Swift structs, enums, or other nice features. This leaves you not writing Swift, but merely "Objective-C with a new syntax". Clearly, `optional` isn't much of an option in Swift. +In this case, you do not have to worry about runtime crashes in Swift, but there is another problem. In Swift, `optional` is *not really* "part of the language" or "pure Swift" — the feature relies on the Objective-C runtime and **it only exists for interoperability with Objective-C**. Any protocol in Swift that contains optional members must be marked as `@objc`. I have [written before]({{ site.url }}{% post_url 2016-06-04-avoiding-objc-in-swift %}) about avoiding `@objc` in your Swift code as much as possible. When `@objc` infiltrates your object graph, nearly everything must inherit from `NSObject` which means you cannot use Swift structs, enums, or other nice features. This leaves you not writing Swift, but merely "Objective-C with a new syntax". Clearly, `optional` isn't much of an option in Swift. ### The 'never optional' solution @@ -67,7 +67,7 @@ One naive solution is to simply never use `optional` or `@optional`. This is eas A better approach is to split up large protocols into smaller ones, and provide a unique property (like a delegate) for each one. Again, consider [`UITableViewDataSource`](https://developer.apple.com/reference/uikit/uitableviewdatasource). There are clear semantic groupings for these methods. It could easily be broken up into multiple protocols and `UITableView` could have a property for each one. Ash Furrow [has a great article](https://ashfurrow.com/blog/protocols-and-swift/) on doing exactly that. Thus, we could reimagine these APIs in the following way: -{% highlight swift %} +```swift class TableView { weak var dataSource: TableViewDataSource? weak var titlesDataSource: TableViewTitlesDataSource? @@ -93,11 +93,11 @@ protocol TableViewReorderingDataSource: class { } // And so on... -{% endhighlight %} +``` This design transfers the "optional-ness" from the protocol itself to an additional optional property on the class. If you want headers and footers in your table view, you can opt-in to those by setting `titlesDataSource`. To opt-out, you can set this property to `nil`. The same applies to `reorderingDataSource`, and so on. This design feels appropriate for `UITableView` at first. Many of the methods are not directly related to one another and there are clear semantic groupings. In practice, however, it feels awkward having to access multiple separate properties to query the same underlying data source. -{% highlight swift %} +```swift // access sections via `dataSource` let sections = dataSource?.tableView(tableView: self, numberOfRowsInSection: 0) @@ -106,7 +106,7 @@ let headerTitle = titlesDataSource?.tableView(tableView: self, titleForHeaderInS // access reordering via `reorderingDataSource` let canMove = reorderingDataSource?.tableView(tableView: self, canMoveRowAtIndexPath: IndexPath(row: 0, section: 0)) -{% endhighlight %} +``` Having these disjoint protocols and properties is not desirable. Despite having nice semantic groupings, all of these methods *are related* in the sense that they all need access to *the same underlying data* in order to work properly together. To accommodate the complete `UITableViewDataSource` protocol, there would be five distinct protocols, each with a corresponding property on `UITableView`. Then you could reorganize the [`UITableViewDelegate`](https://developer.apple.com/reference/uikit/uitableviewdelegate) protocol in the same way, which would have at least 10 protocols and properties. Having this many `dataSource` and `delegate` properties is unintuitive and cumbersome. How can we improve this? @@ -116,7 +116,7 @@ Instead of numerous disjoint protocols, you can design a union of protocols. Thi Adjusting the table view example above: -{% highlight swift %} +```swift class TableView { weak var dataSource: TableViewDataSource? } @@ -131,11 +131,11 @@ protocol TableViewDataSource: class { } // And so on... -{% endhighlight %} +``` Now the table view has a single `dataSource` property. The other protocols still exist, but they are absorbed into the `titles` and `reordering` properties. Another positive aspect of this design is that the opt-in/opt-out behavior for the nested protocols is explicitly declared. The conformer to `TableViewDataSource` can return `nil` to opt-out or return `self` to opt-in to these additional methods. -{% highlight swift %} +```swift class MyDataSource: TableViewDataSource, TableViewTitlesDataSource { func numberOfSections(in tableView: UITableView) -> Int { @@ -168,28 +168,28 @@ class MyDataSource: TableViewDataSource, TableViewTitlesDataSource { return nil } } -{% endhighlight %} +``` Accessing these nested members goes through a single point of access: -{% highlight swift %} +```swift let sections = dataSource?.tableView(tableView: self, numberOfRowsInSection: 0) let headerTitle = dataSource?.titles?.tableView(tableView: self, titleForHeaderInSection: 0) let canMove = dataSource?.reordering?.tableView(tableView: self, canMoveRowAtIndexPath: IndexPath(row: 0, section: 0)) -{% endhighlight %} +``` This reduces the API surface area of `UITableView` by only having a single `dataSource` property instead of five — not to mention the 10 potential `delegate` properties there could have been after splitting up `UITableViewDelegate`. It unifies all of the methods of the data source protocol without resorting to using `optional`, while allowing you to opt out of the additional behavior in a concise way. In the case of Objective-C, the check for `-respondsToSelector:` becomes a simple check for `nil` instead, and the compiler can enforce that the entire protocol is implemented. Overall, it feels cleaner and much more cohesive, especially at the call site. **UPDATE:** [@IanKay](https://twitter.com/IanKay/status/871773445373149184) pointed out that you [can further reduce boilerplate](https://gist.github.com/IanKeen/68eba888221a1a8de03dbbdd8a4dfcf1) from the child protocols by using protocol extensions. For example: -{% highlight swift %} +```swift extension TableViewDataSource { var titles: TableViewTitlesDataSource? { return nil } var reordering: TableViewReorderingDataSource? { return nil } } -{% endhighlight %} +``` See [the full gist](https://gist.github.com/IanKeen/68eba888221a1a8de03dbbdd8a4dfcf1) for more details. diff --git a/_posts/2017-07-16-officially-deprecating-jsqmessagesviewcontroller.md b/_posts/2017-07-16-officially-deprecating-jsqmessagesviewcontroller.md index 9737049d..42c9c170 100644 --- a/_posts/2017-07-16-officially-deprecating-jsqmessagesviewcontroller.md +++ b/_posts/2017-07-16-officially-deprecating-jsqmessagesviewcontroller.md @@ -20,7 +20,7 @@ Beginning immediately, [JSQMessagesViewController](https://github.com/jessesquir For the past year I've gone back and forth, debating with myself about whether or not to continue working on this library or give it up. There is no single reason why I have finally decided to abandon the project, it is more of a *death by a thousand cuts* kind of story. In short, I simply do not have the time nor the motivation to continue working on this project, given its current state. However, I want to emphasize how difficult this is for me to do. I love this project and I loved working on it with the [dozens of contributors](https://github.com/jessesquires/JSQMessagesViewController/graphs/contributors). This is not easy, but if I am going to be honest with myself and with the community, it is time to let it go. (And really, I should have written this 6 months ago.) -I have [written before](/blog/open-source-everything/) about how to successfully maintain open source projects, so this post may seem a bit ironic. Shouldn't I know how to do this? šŸ˜‰ Well, the history of `JSQMessagesViewController` is quite different from the other projects that I maintain. In fact, my other projects and [*that post*](/blog/open-source-everything/) were largely the result of what I learned from all the mistakes I made with `JSQMessagesViewController`. +I have [written before]({{ site.url }}{% post_url 2016-05-22-open-source-everything %}) about how to successfully maintain open source projects, so this post may seem a bit ironic. Shouldn't I know how to do this? Well, the history of `JSQMessagesViewController` is quite different from the other projects that I maintain. In fact, my other projects and [*that post*]({{ site.url }}{% post_url 2016-05-22-open-source-everything %}) were largely the result of what I learned from all the mistakes I made with `JSQMessagesViewController`. This library was **my first ever open source project**. I built it for an app I was working on and extracted this component to put on GitHub. The fact that it grew into what it is today was purely an accident. Within the first few weeks of being on GitHub, it skyrocketed to 1,000 stars. Keep in mind, this was back when that was *a lot of stars* and there were only about 1,000 or so libraries available via CocoaPods. [CocoaPods](https://cocoapods.org) now has over 34 thousands libraries. However, the project did not get off to a great start from the perspective of long-term maintenance. In the early days, there was little or no documentation and certainly no tests. There was no continuous integration, release notes, or even proper semantic versioning. I had no idea what I was doing. But eventually, each of these things were implemented and each time the project got better and more stable. I was learning each step of the way. @@ -28,7 +28,7 @@ Things were great and I was regularly spending time on the project for years. Th Furthermore, while there are many great contributors, unfortunately there is not a clear owner to succeed me and take over the project. -For years, I maintained and supported this library well beyond my own needs — I built features with the community that I never needed nor used for my own apps. In fact, for the majority of the lifetime of this project I was no longer actively using it in any of my own apps. I worked on it because it was fun, and because I had some free time. Now, however, the maintenance burden and my lack of interest and motivation for the project have won. Not to mention, there are *so many* other things I want to build. In a single word, my answer to *why?* is [prioritization](/blog/prioritization/). +For years, I maintained and supported this library well beyond my own needs — I built features with the community that I never needed nor used for my own apps. In fact, for the majority of the lifetime of this project I was no longer actively using it in any of my own apps. I worked on it because it was fun, and because I had some free time. Now, however, the maintenance burden and my lack of interest and motivation for the project have won. Not to mention, there are *so many* other things I want to build. In a single word, my answer to *why?* is [prioritization]({{ site.url }}{% post_url 2017-02-08-prioritization %}). This brings us to today. diff --git a/_posts/2017-07-17-a-story-about-swift-source-compat.md b/_posts/2017-07-17-a-story-about-swift-source-compat.md index 1b63cd93..35817112 100644 --- a/_posts/2017-07-17-a-story-about-swift-source-compat.md +++ b/_posts/2017-07-17-a-story-about-swift-source-compat.md @@ -33,7 +33,7 @@ Adding my project was easy. If you have not added your open source projects, you Here's what [my commit](https://github.com/apple/swift-source-compat-suite/pull/54) included: -{% highlight json %} +```json { "repository": "Git", "url": "https://github.com/jessesquires/JSQDataSourcesKit.git", @@ -64,7 +64,7 @@ Here's what [my commit](https://github.com/apple/swift-source-compat-suite/pull/ } ] } -{% endhighlight %} +``` First, you define all of the metadata about your project and find a commit that compiles with Swift 3. If you tag your releases in git, this is as simple as navigating to your most recent [Swift 3-compatible](https://github.com/jessesquires/JSQDataSourcesKit/releases/tag/6.0.0) release and clicking on [the commit](https://github.com/jessesquires/JSQDataSourcesKit/commit/b764e341713d67ab9c8160929f46e55ad1e2ca07) in the GitHub web interface. This will show you the full commit SHA that you can copy and paste. If you don't tag releases, simply [browse through your commits](https://github.com/jessesquires/JSQDataSourcesKit/commits/develop) until you find one that is suitable. diff --git a/_posts/2017-08-08-customizing-git-log.md b/_posts/2017-08-08-customizing-git-log.md index 0bcfd59a..b20aeaf6 100644 --- a/_posts/2017-08-08-customizing-git-log.md +++ b/_posts/2017-08-08-customizing-git-log.md @@ -31,15 +31,15 @@ Creating [Git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) (o As you can read in [the docs for git-log](https://www.git-scm.com/docs/git-log), there are **a ton** of options to pass to `log`, including an overwhelming amount of ["pretty format"](https://www.git-scm.com/docs/git-log#_pretty_formats) options. There's a more digestible, high-level overview in [section 2.3 of the Git book](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History). After experimenting with these various options, here's what I came up with: -{% highlight bash %} +```bash $ git log --graph --pretty=format:'commit: %C(bold red)%h%Creset %C(red)<%H>%Creset %C(bold magenta)%d %Creset%ndate: %C(bold yellow)%cd %Creset%C(yellow)%cr%Creset%nauthor: %C(bold blue)%an%Creset %C(blue)<%ae>%Creset%n%C(cyan)%s%n%Creset' -{% endhighlight %} +``` Obviously, it is impossible to type this every time you want to run `log`. So you can set an alias called "smartlog". You can also find a [gist here](https://gist.github.com/jessesquires/d0f3fc99be8208394a450ce86443ce7d). -{% highlight bash %} +```bash $ git config --global alias.smartlog "log --graph --pretty=format:'commit: %C(bold red)%h%Creset %C(red)<%H>%Creset %C(bold magenta)%d %Creset%ndate: %C(bold yellow)%cd %Creset%C(yellow)%cr%Creset%nauthor: %C(bold blue)%an%Creset %C(blue)<%ae>%Creset%n%C(cyan)%s%n%Creset'" -{% endhighlight %} +``` Here's a comparison (using [IGListKit](https://github.com/Instagram/IGListKit/commits/master)) between the default `git log` (left) and this new `git smartlog` (right): @@ -49,23 +49,23 @@ The default log displays the commit hash, author, date, and *full* commit messag You've probably noticed that this doesn't exactly match the behavior of `hg smartlog`, which shows only **your** commits. You can fix that by specifying an author, `git smartlog --author='Jesse Squires'`. You can specify anyone on your team, which could also be useful. That command is rather long, so you can set another alias. -{% highlight bash %} +```bash $ git config --global alias.me '!git smartlog --author=Jesse Squires' # usage: git me -{% endhighlight %} +``` Notice that you can reference your previous alias (`smartlog`) within this one. You can use the same technique to abbreviate `smartlog` to `sl`. Yes, you can set aliases for your aliases. -{% highlight bash %} +```bash $ git config --global alias.sl '!git smartlog' # usage: git sl -{% endhighlight %} +``` ### Other useful aliases for Git Here are a few more aliases that I find useful. Some are simply "shortcuts" for existing commands (like `st` for `status`) while others provide more a user-friendly interface for somewhat obscure commands (like `uncommit`). -{% highlight bash %} +```bash alias.co=checkout alias.br=branch alias.cm=commit @@ -75,6 +75,6 @@ alias.uncommit=reset --soft HEAD^ alias.purge=clean -fd alias.dif=diff alias.pick=cherry-pick -{% endhighlight %} +``` Git aliases are pretty powerful and super useful to increase your productivity. Not to mention, they help smooth out Git's rough edges. diff --git a/_posts/2017-09-03-supporting-json-feed.md b/_posts/2017-09-03-supporting-json-feed.md index f79bd506..ea5a0b53 100644 --- a/_posts/2017-09-03-supporting-json-feed.md +++ b/_posts/2017-09-03-supporting-json-feed.md @@ -75,8 +75,8 @@ layout: null Then, you'll need to add a `` tag in the `` section of your site: -{% highlight html %} +```html -{% endhighlight %} +``` That's all. When you run `jekyll build`, your [full feed]({{ site.url }}{{site.feeds.json }}) will be generated. Now, go add JSON Feed support to your blog, too. diff --git a/_posts/2017-09-10-building-a-site-with-jekyll-on-nfsn.md b/_posts/2017-09-10-building-a-site-with-jekyll-on-nfsn.md index 3a7983c6..0e5d09a1 100644 --- a/_posts/2017-09-10-building-a-site-with-jekyll-on-nfsn.md +++ b/_posts/2017-09-10-building-a-site-with-jekyll-on-nfsn.md @@ -187,11 +187,11 @@ The setup described above basically replicates GitHub Pages on your own server, You'll want to follow the steps above, except for when it comes to your local git repo. With GitHub Pages, you'll already have a repo setup on GitHub and cloned locally. You need to set your `remote.origin` to NFSN (to the bare repo you created there), and add a new remote for GitHub. -{% highlight bash %} +```bash # replace username with your usernames git remote set-url origin ssh://@ssh.phx.nearlyfreespeech.net/home/private/site.git git remote add github git@github.com:/.github.io.git -{% endhighlight %} +``` After this change, `git push origin master` will push your master branch to NFSN and `git push github master` will push to GitHub. If you don't want your site to be open source, then don't add the github remote. Push to NFSN and your entire site (and entire git history) should now be copied over to NFSN. diff --git a/_posts/2017-09-18-measuring-compile-times-xcode9.md b/_posts/2017-09-18-measuring-compile-times-xcode9.md index f11861a7..7e89c819 100644 --- a/_posts/2017-09-18-measuring-compile-times-xcode9.md +++ b/_posts/2017-09-18-measuring-compile-times-xcode9.md @@ -13,7 +13,7 @@ image: half_width: false --- -The Swift type-checker remains [a performance bottleneck](https://www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.html) for compile times, though it has [improved](https://github.com/apple/swift/search?utf8=āœ“&q=type+checker+improve&type=Commits) [tremendously](https://github.com/apple/swift/search?utf8=āœ“&q=type+checker+performance&type=Commits) over the past two years. You could even say the type-checker has gone from being [drunk](https://spin.atomicobject.com/2016/04/26/swift-long-compile-time/) to [sober](https://github.com/apple/swift/commit/2cdd7d64e1e2add7bcfd5452d36e7f5fc6c86a03). To help users debug these issues, awhile back [Jordan Rose added](https://github.com/apple/swift/commit/18c75928639acf0ccf0e1fb6729eea75bc09cbd5) a frontend Swift compiler flag that would emit warnings in Xcode for functions that took too long to compile, or rather took too long to type-check. In Xcode 9, there's a new, similar flag for checking expressions. +The Swift type-checker remains [a performance bottleneck](https://www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.html) for compile times, though it has [improved](https://github.com/apple/swift/search?q=type+checker+improve&type=Commits) [tremendously](https://github.com/apple/swift/search?q=type+checker+performance&type=Commits) over the past two years. You could even say the type-checker has gone from being [drunk](https://spin.atomicobject.com/2016/04/26/swift-long-compile-time/) to [sober](https://github.com/apple/swift/commit/2cdd7d64e1e2add7bcfd5452d36e7f5fc6c86a03). To help users debug these issues, awhile back [Jordan Rose added](https://github.com/apple/swift/commit/18c75928639acf0ccf0e1fb6729eea75bc09cbd5) a frontend Swift compiler flag that would emit warnings in Xcode for functions that took too long to compile, or rather took too long to type-check. In Xcode 9, there's a new, similar flag for checking expressions. diff --git a/_posts/2017-09-24-when-your-app-is-used-in-unexpected-ways.md b/_posts/2017-09-24-when-your-app-is-used-in-unexpected-ways.md index f0305984..f4a72904 100644 --- a/_posts/2017-09-24-when-your-app-is-used-in-unexpected-ways.md +++ b/_posts/2017-09-24-when-your-app-is-used-in-unexpected-ways.md @@ -13,11 +13,11 @@ image: half_width: false --- -[PlanGrid](https://www.plangrid.com) is a [productivity app](https://itunes.apple.com/us/app/plangrid-construction-collaboration/id498795789) for construction fieldworkers. The easiest way to explain it to software developers is that it's like an IDE, Git, and GitHub or JIRA — but for construction. Think of all the amazing software tools we have to do our jobs as programmers. The equivalent tools for construction simply did not exist before PlanGrid, and they still have a lot of room to grow. +[PlanGrid](https://www.plangrid.com) is a [productivity app](https://apps.apple.com/us/app/plangrid-construction-collaboration/id498795789) for construction fieldworkers. The easiest way to explain it to software developers is that it's like an IDE, Git, and GitHub or JIRA — but for construction. Think of all the amazing software tools we have to do our jobs as programmers. The equivalent tools for construction simply did not exist before PlanGrid, and they still have a lot of room to grow. As software developers, we build software for specific purposes. We anticipate that people will use an app in certain ways. Yet, we often discover that users are behaving differently than we expected. They hack a custom, "unsupported" workflow to workaround an app's unintended limitations. Once we realize this, we have the power to turn these user workarounds into first-class features. However, sometimes we find that our apps are being used in totally different, unimaginable ways. -At PlanGrid, we recently discovered that the app was [being used as a digital archaeological tool](http://popular-archaeology.com/issue/fall-2017/article/adapting-plangrid-to-archaeology). +At PlanGrid, we recently discovered that the app was [being used as a digital archaeological tool](https://popular-archaeology.com/article/adapting-plangrid-to-archaeology/). diff --git a/_posts/2017-10-01-floating-point-swift-ulp-and-epsilon.md b/_posts/2017-10-01-floating-point-swift-ulp-and-epsilon.md index d2f49db7..23c78191 100644 --- a/_posts/2017-10-01-floating-point-swift-ulp-and-epsilon.md +++ b/_posts/2017-10-01-floating-point-swift-ulp-and-epsilon.md @@ -97,45 +97,45 @@ Note that with this representation, positive and negative zero (`+0` and `-0`) a Let's look at an example in base-10. We can represent 123.45 with a significand of 12345 and exponent of -2: `123.45 = 12345 * 10eāˆ’2`. In base-2, computing a value from these three components is a bit more complicated but conceptually the same. Swift provides a clear and expressive API that can really help us understand how all of this works. -{% highlight swift %} +```swift let value = Float(0.15625) // 1/8 + 1/32 value.sign // plus value.exponent // -3 value.significand // 1.25 -{% endhighlight %} +``` We can recompute the decimal value from its component parts. Note that the `radix`, or base, is 2 — as in base-2 for binary. -{% highlight swift %} +```swift // significand * 2^exponent Float(value.significand) * powf(Float(Float.radix), Float(value.exponent)) // 0.15625 -{% endhighlight %} +``` Additionally, Swift's APIs allow us to explore the memory layout. We can look at the bit patterns and verify them with this [handy IEEE-754 floating-point converter](https://www.h-schmidt.net/FloatConverter/IEEE754.html). -{% highlight swift %} +```swift // 0.15625 value.exponentBitPattern // 124 value.significandBitPattern // 2097152 -{% endhighlight %} +``` We can also check the bit counts for each component: -{% highlight swift %} +```swift Float.exponentBitCount // 8, bits for the exponent Float.significandBitCount // 23, bits for the significand Double.exponentBitCount // 11, bits for the exponent Double.significandBitCount // 52, bits for the significand -{% endhighlight %} +``` ### Defining `ulp` Surprisingly, the IEEE standard doesn't define `ulpOfOne` (or [machine epsilon](https://en.wikipedia.org/wiki/Machine_epsilon)) explicitly, so there are a couple of varying definitions. However, most standard libraries provide constants for these values. The most prevalent is the [ISO C Standard](http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1570.pdf) — `1.19e-07` for 32-bit values (`Float`) and `2.22e-16` for 64-bit values (`Double`). As expected, this is what we see in Swift: -{% highlight swift %} +```swift Float.ulpOfOne // 1.192093e-07, or // 0.00000011920928955078125 @@ -143,35 +143,35 @@ Float.ulpOfOne Double.ulpOfOne // 2.220446049250313e-16, or // 0.00000000000000022204460492503130808472633361816406250 -{% endhighlight %} +``` Given these initial epsilon or `ulpOfOne` values, [we can compute](https://en.wikipedia.org/wiki/Unit_in_the_last_place#Definition) the `ulp` for any value `v` with an exponent `exp` as: `epsilon * 2^exp`, where 2 is the radix, or base. -{% highlight swift %} +```swift let value = Float(3.14) let ulpOfValue = Float.ulpOfOne * powf(2.0, Float(value.exponent)) ulpOfValue // 0.00000023841857910156250 value.ulp // 0.00000023841857910156250 -{% endhighlight %} +``` Again, Swift provides a great, readable API for manipulating and exploring the properties of floating-point values. For example, for any value we can check [`.nextUp`](https://developer.apple.com/documentation/swift/floatingpoint/1848104-nextup) to see the next representable value. Given what we've learned so far, we can intuitively reason about what the next number (`.nextUp`) must be and verify our result. -{% highlight swift %} +```swift let value = Float(1.0) value.ulp // 0.00000011920928955078125 value + value.ulp // 1.00000011920928955078125 value.nextUp // 1.00000011920928955078125 -{% endhighlight %} +``` -{% highlight swift %} +```swift let value = Float(1_000.0) value.ulp // 0.00006103515625000000000 value + value.ulp // 1000.00006103515625000000000 value.nextUp // 1000.00006103515625000000000 -{% endhighlight %} +``` -{% highlight swift %} +```swift let value = Float(3.14) // actually 3.14000010490417480468750 -- because rounding @@ -179,21 +179,21 @@ value // 3.14000010490417480468750 value.ulp // 0.00000023841857910156250 value + value.ulp // 3.14000034332275390625000 value.nextUp // 3.14000034332275390625000 -{% endhighlight %} +``` Notice that the `ulp` of 1 is not the same as the `ulp` of 1,000. For each floating-point number `ulp` varies. In fact, the precision of a floating-point value is proportional to its magnitude. The larger a value, the less precise. -{% highlight swift %} +```swift let value = Float(1_000_000_000.0) value.ulp // 64.0 value.nextUp // 1000000064.0 -{% endhighlight %} +``` ### Viewing the source We can view the Swift standard library source, which lives in [`stdlib/public/core/ FloatingPointTypes.swift.gyb`](https://github.com/apple/swift/blob/master/stdlib/public/core/FloatingPointTypes.swift.gyb#L541-L562). If you've never seen `.gyb` ('generate your boilerplate') files, read [Ole Begemann's post](https://oleb.net/blog/2016/10/swift-stdlib-source/). Per Ole's instructions, we can generate the specific implementation for `Float`. -{% highlight swift %} +```swift public var ulp: Float { if !isFinite { return Float.nan } if exponentBitPattern > UInt(Float.significandBitCount) { @@ -216,13 +216,13 @@ public var ulp: Float { exponentBitPattern: 0, significandBitPattern: 1) } -{% endhighlight %} +``` Surprising at an initial glance, this is not the simple formula noted above (`epsilon * 2^exponent`). First there are some edge cases to handle, like `Float.nan.ulp` which is `nan`. Then it constructs a new `Float` after computing its constituent components — the sign, exponent, and significand. This code eventually calls into the public initializer: `init(sign: exponentBitPattern: significandBitPattern:)`. Note that the final return is equivalent to `Float.leastNonzeroMagnitude` (or `FLT_MIN`). We can view the implementation of this initializer. We see a lot of [bit manipulation](https://en.wikipedia.org/wiki/Bit_manipulation), namely [bitwise AND](https://developer.apple.com/documentation/swift/binaryinteger/2886547) (`&`) and [masking left shift](https://developer.apple.com/documentation/swift/fixedwidthinteger/2924902) (`&<<`). -{% highlight swift %} +```swift public init(sign: FloatingPointSign, exponentBitPattern: UInt, significandBitPattern: UInt32) { @@ -237,19 +237,19 @@ public init(sign: FloatingPointSign, exponent &<< UInt32(Float.significandBitCount) | significand) } -{% endhighlight %} +``` This initializer eventually calls into `init(bitPattern:)`, where it finally constructs a primitive LLVM 32-bit float (FPIEEE32) from the raw bit pattern. -{% highlight swift %} +```swift public init(bitPattern: UInt32) { self.init(_bits: Builtin.bitcast_Int32_FPIEEE32(bitPattern._value)) } -{% endhighlight %} +``` We can break this down and observe each step in a Swift playground. For private APIs like `Float._infinityExponent`, we can look at the source and define them inline. -{% highlight swift %} +```swift // starting value let value = Float(3.1415) @@ -285,18 +285,18 @@ let bitPattern = signMaskLeftShift | exponentMaskLeftShift | significand // 8808 // 3. initialize with the computed bit pattern let finalUlp = Float(bitPattern: bitPattern) // 2.384186e-07, or 0.00000023841857910156250 -{% endhighlight %} +``` This code is admittedly quite difficult to follow, but suffice to say it is equivalent to what we originally computed above. -{% highlight swift %} +```swift let value = Float(3.1415) let computedUlp = Float.ulpOfOne * powf(Float(Float.radix), Float(value.exponent)) value // 3.14149999618530273437500 computedUlp // 0.00000023841857910156250 value.ulp // 0.00000023841857910156250 -{% endhighlight %} +``` ### Conclusion diff --git a/_posts/2017-12-28-swift-weekly-brief-hiatus.md b/_posts/2017-12-28-swift-weekly-brief-hiatus.md index 956fbca9..5842925d 100644 --- a/_posts/2017-12-28-swift-weekly-brief-hiatus.md +++ b/_posts/2017-12-28-swift-weekly-brief-hiatus.md @@ -26,7 +26,7 @@ Next week's issue of [Swift Weekly Brief](https://swiftweekly.github.io) will be ### Why now? -I'm ready to move on and focus on other projects and priorities, similar to [other projects I've stopped maintaining](/blog/officially-deprecating-jsqmessagesviewcontroller/). The 100th issue is a notable milestone, and it happened to arrive at a great time — the first (and now last) issue of the new year. The flow of Swift evolution proposals has stabilized to a reasonable number, and the new forums are coming soon. It feels like the right time and place for me to stop — or hand over the reins to someone else. +I'm ready to move on and focus on other projects and priorities, similar to [other projects I've stopped maintaining]({{ site.url }}{% post_url 2017-07-16-officially-deprecating-jsqmessagesviewcontroller %}). The 100th issue is a notable milestone, and it happened to arrive at a great time — the first (and now last) issue of the new year. The flow of Swift evolution proposals has stabilized to a reasonable number, and the new forums are coming soon. It feels like the right time and place for me to stop — or hand over the reins to someone else. The majority of issues were a blast to write. It was an incredibly fun project to run, and I learned a ton. However, at times it was stressful and felt like a burden. There was (admittedly self-imposed) pressure to publish every single week, and I was not always prepared or enthusiastic. There was definitely burnout. After taking breaks while other contributors wrote issues, I was always excited to return and write the next one. @@ -34,7 +34,7 @@ Finally, as mentioned in the newsletter, the new [Swift.org forums](https://foru ### The good news, or maybe you can help -I have always viewed the newsletter just like any other open source project. There is a [GitHub organization](https://github.com/SwiftWeekly), [code of conduct](https://github.com/SwiftWeekly/swiftweekly.github.io/blob/master/CODE_OF_CONDUCT.md), and [contributing guide](https://github.com/SwiftWeekly/swiftweekly.github.io/blob/master/CONTRIBUTING.md). The good news is that **this project is very healthy**. We have established a simple and painless process for contributing and publishing new issues. We have great docs, tweets to the [official Twitter account](https://twitter.com/swiftlybrief) are automated, and we are setup [on Travis CI](https://travis-ci.org/SwiftWeekly/swiftweekly.github.io) so you can be sure that you will not accidentally break anything. **Anyone from the community could take over this project.** You only need some motivation, a passion for Swift, some free time, and the ability to write markdown. šŸ˜„ +I have always viewed the newsletter just like any other open source project. There is a [GitHub organization](https://github.com/SwiftWeekly), [code of conduct](https://github.com/SwiftWeekly/.github/blob/master/CODE_OF_CONDUCT.md), and [contributing guide](https://github.com/SwiftWeekly/.github/blob/master/CONTRIBUTING.md). The good news is that **this project is very healthy**. We have established a simple and painless process for contributing and publishing new issues. We have great docs, tweets to the [official Twitter account](https://twitter.com/swiftlybrief) are automated, and we are setup [on Travis CI](https://travis-ci.org/SwiftWeekly/swiftweekly.github.io) so you can be sure that you will not accidentally break anything. **Anyone from the community could take over this project.** You only need some motivation, a passion for Swift, some free time, and the ability to write markdown. šŸ˜„ ### Transitioning to a new owner diff --git a/_posts/2018-02-25-replacing-google-with-duckduckgo.md b/_posts/2018-02-25-replacing-google-with-duckduckgo.md index 7c1c2f01..e9fd78d5 100644 --- a/_posts/2018-02-25-replacing-google-with-duckduckgo.md +++ b/_posts/2018-02-25-replacing-google-with-duckduckgo.md @@ -50,7 +50,7 @@ Google allows you to create a free [custom search component](https://cse.google. Creating a [custom DuckDuckGo search](https://duckduckgo.com/search_box) is much simpler. They provide an [`