Skip to content

Commit

Permalink
Migrate article updates from site relaunch
Browse files Browse the repository at this point in the history
Update section title

Note deprecation of (UI)WebView

Update and rename WKWebView article

Fix link to clangwarnings.com

Remove incorrect statement about Apple Developer Program membership

Update Network Link Conditioner post

Update revision history

Copy editing

Fix Swift version for Bug Reporting

Update Bug Reporting

Fix revision date

Update excerpt for Swift Documentation

Additional revision for Swift Documentation

Migrate to custom syntax theme

Copy edit

Add announcement

Fix asset tags in articles

Add extra Kramdown tags to process HTML tables correctly

Fix HTML in Launch Arguments post

http -> https

Fix objc language tag for code

Add missing posts

Update posts to use {% asset %} tag

Use GFM code block syntax
  • Loading branch information
mattt committed Jul 25, 2018
1 parent f999ad5 commit 9e2ed08
Show file tree
Hide file tree
Showing 140 changed files with 3,049 additions and 3,144 deletions.
2 changes: 1 addition & 1 deletion 2012-07-07-nsindexset.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: NSIndexSet
author: Mattt Thompson
author: Mattt
category: Cocoa
tags: nshipster
excerpt: "NSIndexSet (like its mutable counterpart, NSMutableIndexSet) is a sorted collection of unique unsigned integers. Think of it like an NSRange that supports non-contiguous series. It has wicked fast operations for finding indexes in ranges or set intersections, and comes with all of the convenience methods you'd expect in a Foundation collection class."
Expand Down
8 changes: 3 additions & 5 deletions 2012-07-14-nscache.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: NSCache
author: Mattt Thompson
author: Mattt
category: Cocoa
tags: nshipster
excerpt: "Poor NSCache, always being overshadowed by NSMutableDictionary. It's as if no one knew how it provides all of that garbage collection behavior that developers take great pains to re-implement themselves."
status:
swift: 2.2
reviewed: April 10, 2016
swift: 2.0
reviewed: September 8, 2015
---

Poor `NSCache`, always being overshadowed by `NSMutableDictionary`. It's as if no one knew how it provides all of that garbage collection behavior that developers take great pains to re-implement themselves.
Expand Down Expand Up @@ -59,5 +59,3 @@ extension NSCache {
}
}
```

> **Note:** Due to changes in Objective-C generics in Swift 3, the subscript given above will only work in Swift 2.3 and earlier.
31 changes: 15 additions & 16 deletions 2012-07-24-nssortdescriptor.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
---
title: NSSortDescriptor
author: Mattt Thompson
author: Mattt
category: Cocoa
tags: nshipster
excerpt: "Sorting: it's the mainstay of Computer Science 101 exams and whiteboarding interview questions. But when was the last time you actually needed to know how to implement Quicksort yourself?"
status:
swift: 2.2
reviewed: April 10, 2016
swift: 1.1
---

Sorting: it's the mainstay of Computer Science 101 exams and whiteboarding interview questions. But when was the last time you actually needed to know how to implement Quicksort yourself?

When making apps, sorting is just something you can assume to be fast, and utility is a function of convenience and clarity of intention. And when it comes to that, you'd be hard-pressed to find a better implementation than Foundation's `NSSortDescriptor`.

* * *
---

`NSSortDescriptor` objects are constructed with the following parameters:

Expand All @@ -28,7 +27,7 @@ Collection classes like `NSArray` and `NSSet` have methods to return sorted arra

To put that into more practical terms, consider a `Person` class with properties for `firstName` & `lastName` of type `NSString *`, and `age`, which is an `NSUInteger`.

~~~{swift}
```swift
class Person: NSObject {
let firstName: String
let lastName: String
Expand All @@ -44,9 +43,9 @@ class Person: NSObject {
return "\(firstName) \(lastName)"
}
}
~~~
```

~~~{objective-c}
```objc
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
Expand All @@ -60,28 +59,28 @@ class Person: NSObject {
}

@end
~~~
```
Given the following dataset:
| `firstName` | `lastName` | `age` |
|-------------|------------|-------|
| ----------- | ---------- | ----- |
| Alice | Smith | 24 |
| Bob | Jones | 27 |
| Charlie | Smith | 33 |
| Quentin | Alberts | 31 |
Here are some of the different ways they can be sorted by combinations of `NSSortDescriptor`:
~~~{swift}
```swift
let alice = Person(firstName: "Alice", lastName: "Smith", age: 24)
let bob = Person(firstName: "Bob", lastName: "Jones", age: 27)
let charlie = Person(firstName: "Charlie", lastName: "Smith", age: 33)
let quentin = Person(firstName: "Quentin", lastName: "Alberts", age: 31)
let people = [alice, bob, charlie, quentin]
let firstNameSortDescriptor = NSSortDescriptor(key: "firstName", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))
let lastNameSortDescriptor = NSSortDescriptor(key: "lastName", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))
let firstNameSortDescriptor = NSSortDescriptor(key: "firstName", ascending: true, selector: "localizedStandardCompare:")
let lastNameSortDescriptor = NSSortDescriptor(key: "lastName", ascending: true, selector: "localizedStandardCompare:")
let ageSortDescriptor = NSSortDescriptor(key: "age", ascending: false)
let sortedByAge = (people as NSArray).sortedArrayUsingDescriptors([ageSortDescriptor])
Expand All @@ -92,9 +91,9 @@ let sortedByFirstName = (people as NSArray).sortedArrayUsingDescriptors([firstNa
let sortedByLastNameFirstName = (people as NSArray).sortedArrayUsingDescriptors([lastNameSortDescriptor, firstNameSortDescriptor])
// "Quentin Alberts", "Bob Jones", "Alice Smith", "Charlie Smith"
~~~
```

~~~{objective-c}
```objc
NSArray *firstNames = @[ @"Alice", @"Bob", @"Charlie", @"Quentin" ];
NSArray *lastNames = @[ @"Smith", @"Jones", @"Smith", @"Alberts" ];
NSArray *ages = @[ @24, @27, @33, @31 ];
Expand Down Expand Up @@ -127,9 +126,9 @@ NSLog(@"By first name: %@", [people sortedArrayUsingDescriptors:@[firstNameSortD

NSLog(@"By last name, first name: %@", [people sortedArrayUsingDescriptors:@[lastNameSortDescriptor, firstNameSortDescriptor]]);
// "Quentin Alberts", "Bob Jones", "Alice Smith", "Charlie Smith"
~~~
```
* * *
---
`NSSortDescriptor` can be found throughout Foundation and other system frameworks, playing an especially prominent role in Core Data. Anytime your own classes need to define sort ordering, follow the convention of specifying a `sortDescriptors` parameter as appropriate.
Expand Down
36 changes: 18 additions & 18 deletions 2012-07-31-nsdatecomponents.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: NSDateComponents
author: Mattt Thompson
author: Mattt
category: Cocoa
excerpt: "NSDateComponents serves an important role in Foundation's date and time APIs. By itself, it's nothing impressive—just a container for information about a date (its month, year, day of month, week of year, or whether that month is a leap month). However, combined with NSCalendar, NSDateComponents becomes a remarkably convenient interchange format for calendar calculations."
status:
Expand All @@ -16,21 +16,21 @@ Whereas dates represent a particular moment in time, date components depend on w

`NSDateComponents` can be initialized and manipulated manually, but most often, they're extracted from a specified date, using `NSCalendar -components:fromDate:`:

~~~{swift}
```swift
let calendar = NSCalendar.currentCalendar()
let date = NSDate()
let components = calendar.components([.Month, .Day], fromDate: date)
~~~
```

~~~{objective-c}
```objc
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];
[calendar components:(NSCalendarUnitDay | NSCalendarUnitMonth) fromDate:date];
~~~
```
The `components` parameter is a [bitmask](http://en.wikipedia.org/wiki/Bitmask) of the date component values to retrieve, with many to choose from:
~~~{swift}
```swift
NSCalendarUnit.Era
NSCalendarUnit.Year
NSCalendarUnit.Month
Expand All @@ -46,9 +46,9 @@ NSCalendarUnit.WeekOfYear
NSCalendarUnit.YearForWeekOfYear
NSCalendarUnit.Calendar
NSCalendarUnit.TimeZone
~~~
```

~~~{objective-c}
```objc
NSCalendarUnitEra
NSCalendarUnitYear
NSCalendarUnitMonth
Expand All @@ -64,15 +64,15 @@ NSCalendarUnitWeekOfYear
NSCalendarUnitYearForWeekOfYear
NSCalendarUnitCalendar
NSCalendarUnitTimeZone
~~~
```

> Since it would be expensive to compute all of the possible values, specify only the components that will be used in subsequent calculations (joining with `|`, the bitwise `OR` operator).
## Relative Date Calculations

`NSDateComponents` objects can be used to do relative date calculations. To determine the date yesterday, next week, or 5 hours and 30 minutes from now, use `NSCalendar -dateByAddingComponents:toDate:options:`:
`NSDateComponents` objects can be used to do relative date calculations. To determining the date yesterday, next week, or 5 hours and 30 minutes from now, use `NSCalendar -dateByAddingComponents:toDate:options:`:

~~~{swift}
```swift
let calendar = NSCalendar.currentCalendar()
let date = NSDate()

Expand All @@ -81,9 +81,9 @@ components.weekOfYear = 1
components.hour = 12

print("1 week and 12 hours from now: \(calendar.dateByAddingComponents(components, toDate: date, options: []))")
~~~
```

~~~{objective-c}
```objc
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];

Expand All @@ -92,13 +92,13 @@ NSDateComponents *components = [[NSDateComponents alloc] init];
[components setHour:12];

NSLog(@"1 week and twelve hours from now: %@", [calendar dateByAddingComponents:components toDate:date options:0]);
~~~
```
## Creating Dates from Components
Perhaps the most powerful feature of `NSDateComponents`, however, is the ability to go the opposite direction—creating an `NSDate` object from components. `NSCalendar -dateFromComponents:` is the method used for this purpose:
~~~{swift}
```swift
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
let components = NSDateComponents()
Expand All @@ -110,9 +110,9 @@ components.minute = 20
components.second = 0
let date = calendar?.dateFromComponents(components)
~~~
```

~~~{objective-c}
```objc
NSCalendar *calendar = [NSCalendar currentCalendar];

NSDateComponents *components = [[NSDateComponents alloc] init];
Expand All @@ -124,7 +124,7 @@ NSDateComponents *components = [[NSDateComponents alloc] init];
[components setSecond:0];

NSDate *date = [calendar dateFromComponents:components];
~~~
```
What's particularly interesting about this approach is that a date can be determined by information other than the normal month/day/year approach. So long as a date can be uniquely determined from the provided information, you'll get a result. For example, specifying the year 2013, and the 316th day of the year would return an `NSDate` for 11/12/2013 at midnight (because no time was specified, all time components default to 0).
Expand Down
18 changes: 9 additions & 9 deletions 2012-08-06-cfstringtransform.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: CFStringTransform
author: Mattt Thompson
author: Mattt
category: Cocoa
tags: nshipster, popular
excerpt: "NSString is the crown jewel of Foundation. But as powerful as it is, one would be remiss not to mention its toll-free bridged cousin, CFMutableString—or more specifically, CFStringTransform."
Expand Down Expand Up @@ -112,31 +112,31 @@ One of the more practical applications for string transformation is to normalize

For example, let's say you want to build a searchable index of movies on the device, which includes greetings from around the world:

~~~{swift}
```swift
var mutableString = NSMutableString(string: "Hello! こんにちは! สวัสดี! مرحبا! 您好!") as CFMutableStringRef
~~~
```

- First, apply the `kCFStringTransformToLatin` transform to transliterate all non-English text into a Latin alphabetic representation.

~~~{swift}
```swift
CFStringTransform(mutableString, nil, kCFStringTransformToLatin, Boolean(0))
~~~
```

> Hello! こんにちは! สวัสดี! مرحبا! 您好! →
> Hello! kon'nichiha! s̄wạs̄dī! mrḥbạ! nín hǎo!
- Next, apply the `kCFStringTransformStripCombiningMarks` transform to remove any diacritics or accents.

~~~{swift}
```swift
CFStringTransform(mutableString, nil, kCFStringTransformStripCombiningMarks, Boolean(0))
~~~
```

> Hello! kon'nichiha! s̄wạs̄dī! mrḥbạ! nín hǎo! →
> Hello! kon'nichiha! swasdi! mrhba! nin hao!
- Finally, downcase the text with `CFStringLowercase`, and split the text into tokens with [`CFStringTokenizer`](https://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFStringTokenizerRef/Reference/reference.html) to use as an index for the text.

~~~{swift}
```swift
let tokenizer = CFStringTokenizerCreate(nil, mutableString, CFRangeMake(0, CFStringGetLength(mutableString)), 0, CFLocaleCopyCurrent())

var mutableTokens: [String] = []
Expand All @@ -147,7 +147,7 @@ do {
let token = CFStringCreateWithSubstring(nil, mutableString, range) as NSString
mutableTokens.append(token)
} while type != .None
~~~
```

> (hello, kon'nichiha, swasdi, mrhba, nin, hao)
Expand Down
29 changes: 14 additions & 15 deletions 2012-08-13-nsincrementalstore.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: NSIncrementalStore
author: Mattt Thompson
author: Mattt
category: Cocoa
excerpt: Even for a blog dedicated to obscure APIs, `NSIncrementalStore` sets a new standard. It was introduced in iOS 5, with no more fanfare than the requisite entry in the SDK changelog. Ironically, it is arguably the most important thing to come out of iOS 5, which will completely change the way we build apps from here on out.
status:
Expand Down Expand Up @@ -40,7 +40,7 @@ With `NSIncrementalStore`, developers now have a sanctioned, reasonable means to

`+initialize` is automatically called the first time a class is loaded, so this is a good place to register with `NSPersistentStoreCoordinator`:

~~~{swift}
```swift
class CustomIncrementalStore: NSIncrementalStore {
override class func initialize() {
NSPersistentStoreCoordinator.registerStoreClass(self, forStoreType:self.type)
Expand All @@ -50,24 +50,23 @@ class CustomIncrementalStore: NSIncrementalStore {
return NSStringFromClass(self)
}
}
~~~
```


~~~{objective-c}
```objc
+ (void)initialize {
[NSPersistentStoreCoordinator registerStoreClass:self forStoreType:[self type]];
}

+ (NSString *)type {
return NSStringFromClass(self);
}
~~~
```

### `-loadMetadata:`

`loadMetadata:` is where the incremental store has a chance to configure itself. There is, however, a bit of Kabuki theater boilerplate that's necessary to get everything set up. Specifically, you need to set a UUID for the store, as well as the store type. Here's what that looks like:

~~~{swift}
```swift
override func loadMetadata(error: NSErrorPointer) -> Bool {
self.metadata = [
NSStoreUUIDKey: NSProcessInfo().globallyUniqueString,
Expand All @@ -76,14 +75,14 @@ override func loadMetadata(error: NSErrorPointer) -> Bool {

return true
}
~~~
```

~~~{objective-c}
```objc
NSMutableDictionary *mutableMetadata = [NSMutableDictionary dictionary];
[mutableMetadata setValue:[[NSProcessInfo processInfo] globallyUniqueString] forKey:NSStoreUUIDKey];
[mutableMetadata setValue:[[self class] type] forKey:NSStoreTypeKey];
[self setMetadata:mutableMetadata];
~~~
```
### `-executeRequest:withContext:error:`
Expand Down Expand Up @@ -135,13 +134,13 @@ Finally, this method is called before `executeRequest:withContext:error:` with a
This usually corresponds with a write to the persistence layer, such as an `INSERT` statement in SQL. If, for example, the row corresponding to the object had an auto-incrementing `id` column, you could generate an objectID with:
~~~{swift}
```swift
self.newObjectIDForEntity(entity, referenceObject: rowID)
~~~
```

~~~{objective-c}
```objc
[self newObjectIDForEntity:entity referenceObject:[NSNumber numberWithUnsignedInteger:rowID]];
~~~
```
## Roll Your Own Core Data Backend
Expand All @@ -159,6 +158,6 @@ What this means is that you can now write apps that communicate with a webservic
Since the store abstracts all of the implementation details of the API away, you can write expressive fetch requests and object relationships from the start. No matter how bad or incomplete an API may be, you can change all of that mapping independently of the business logic of the client.
* * *
---
Even though `NSIncrementalStore` has been around since iOS 5, we're still a long way from even beginning to realize its full potential. The future is insanely bright, so you best don your aviators, grab an iced latte and start coding something amazing.
Loading

0 comments on commit 9e2ed08

Please sign in to comment.