Skip to content

Commit

Permalink
Merge pull request NSHipster#328 from 0x7fffffff/master
Browse files Browse the repository at this point in the history
Updates to UISplitViewController / NSHashTable & NSMapTable / AVSpeechSynthesizer
  • Loading branch information
natecook1000 committed Sep 15, 2015
2 parents 9d00606 + be51787 commit 0c45b6b
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 12 deletions.
37 changes: 34 additions & 3 deletions 2013-08-19-nshashtable-and-nsmaptable.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ category: Cocoa
tags: nshipster
excerpt: "NSSet and NSDictionary, along with NSArray are the workhorse collection classes of Foundation. Unlike other standard libraries, implementation details are hidden from developers, allowing them to write simple code and trust that it will be (reasonably) performant."
status:
swift: t.b.c.
swift: 2.0
reviewed: September 11, 2015
---

`NSSet` and `NSDictionary`, along with `NSArray` are the workhorse collection classes of Foundation. Unlike [ other standard libraries](http://en.wikipedia.org/wiki/Java_collections_framework), implementation details are [hidden](http://ridiculousfish.com/blog/posts/array.html) from developers, allowing them to write simple code and trust that it will be (reasonably) performant.
Expand All @@ -28,6 +29,15 @@ So without further ado, here's everything you need to know about two of the more

### Usage

~~~{swift}
let hashTable = NSHashTable(options: .CopyIn)
hashTable.addObject("foo")
hashTable.addObject("bar")
hashTable.addObject(42)
hashTable.removeObject("bar")
print(hashTable.allObjects)
~~~

~~~{objective-c}
NSHashTable *hashTable = [NSHashTable hashTableWithOptions:NSPointerFunctionsCopyIn];
[hashTable addObject:@"foo"];
Expand Down Expand Up @@ -59,6 +69,13 @@ NSLog(@"Members: %@", [hashTable allObjects]);

Instances where one might use `NSMapTable` include non-copyable keys and storing weak references to keyed delegates or another kind of weak object.

~~~{swift}
let delegate: AnyObject = ...
let mapTable = NSMapTable(keyOptions: .StrongMemory, valueOptions: .WeakMemory)
mapTable.setObject(delegate, forKey: "foo")
print("Keys: \(mapTable.keyEnumerator().allObjects)")
~~~

~~~{objective-c}
id delegate = ...;
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
Expand All @@ -80,17 +97,31 @@ Equal to `NSPointerFunctionsObjectPointerPersonality`.

`NSMapTable` doesn't implement [object subscripting](http://nshipster.com/object-subscripting/), but it can be trivially added in a category. `NSDictionary`'s `NSCopying` requirement for keys belongs to `NSDictionary` alone:

~~~{swift}
extension NSMapTable {
subscript(key: AnyObject?) -> AnyObject? {
get {
return objectForKey(key)
}
set {
setObject(newValue, forKey: key)
}
}
}
~~~

~~~{objective-c}
@implementation NSMapTable (NSHipsterSubscripting)
- (id)objectForKeyedSubscript:(id)key
{
return [self objectForKey:key];
return [self objectForKey:key];
}
- (void)setObject:(id)obj forKeyedSubscript:(id)key
{
[self setObject:obj forKey:key];
[self setObject:obj forKey:key];
}
@end
Expand Down
7 changes: 4 additions & 3 deletions 2014-03-31-avspeechsynthesizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ author: Mattt Thompson
category: Cocoa
excerpt: "Though we're a long way off from Hal or Her, we should never forget about the billions of other people out there for us to talk to."
status:
swift: 1.1
swift: 2.0
reviewed: September 10, 2015
---

Though we're a long way off from [_Hal_](https://www.youtube.com/watch?v=ARJ8cAGm6JE) or [_Her_](https://www.youtube.com/watch?v=WzV6mXIOVl4), we should never forget about the billions of other people out there for us to talk to.
Expand Down Expand Up @@ -104,13 +105,13 @@ var utteranceLabel: UILabel!

// MARK: AVSpeechSynthesizerDelegate

func speechSynthesizer(synthesizer: AVSpeechSynthesizer!, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance!) {
func speechSynthesizer(synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
let mutableAttributedString = NSMutableAttributedString(string: utterance.speechString)
mutableAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: characterRange)
utteranceLabel.attributedText = mutableAttributedString
}

func speechSynthesizer(synthesizer: AVSpeechSynthesizer!, didFinishSpeechUtterance utterance: AVSpeechUtterance!) {
func speechSynthesizer(synthesizer: AVSpeechSynthesizer, didFinishSpeechUtterance utterance: AVSpeechUtterance) {
utteranceLabel.attributedText = NSAttributedString(string: utterance.speechString)
}
```
Expand Down
66 changes: 60 additions & 6 deletions 2014-11-03-uisplitviewcontroller.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ author: Natasha Murashev
category: Cocoa
excerpt: "The introduction of iPhone 6+ brought on a new importance for UISplitViewController. With just a few little tweaks, an app can now become Universal, with Apple handling most of the UI logic for all the different screen sizes."
status:
swift: 1.0
swift: 2.0
reviewed: September 11, 2015
---

The introduction of iPhone 6+ brought on a new importance for `UISplitViewController`. With just a few little tweaks, an app can now become Universal, with Apple handling most of the UI logic for all the different screen sizes.
Expand Down Expand Up @@ -71,7 +72,7 @@ Even when the navigation controller is in place, the UI is not that much better

The simplest way to fix this issue would be to somehow indicate that there is more to the app than what's currently on-screen. Luckily, the UISplitViewController has a **displayModeButtonItem**, which can be added to the navigation bar:

```swift
~~~{swift}
override func viewDidLoad() {
super.viewDidLoad()
Expand All @@ -80,7 +81,18 @@ override func viewDidLoad() {
navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem()
navigationItem.leftItemsSupplementBackButton = true
}
```
~~~

~~~{objective-c}
- (void)viewDidLoad {
[super viewDidLoad];
// ...
self.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
self.navigationItem.leftItemsSupplementBackButton = YES;
}
~~~

Build and Run on the iPad again, and now the user gets a nice indication of how to get at the rest of the app:

Expand All @@ -98,7 +110,7 @@ There is one more optimization we can do for the iPhone 6+ via [`UISplitViewCont

When the user first launches the app, we can make the master view controller fully displayed until the user selects a list item:

```swift
~~~{swift}
import UIKit
class SelectColorTableViewController: UITableViewController, UISplitViewControllerDelegate {
Expand All @@ -122,11 +134,53 @@ class SelectColorTableViewController: UITableViewController, UISplitViewControll
// MARK: - UISplitViewControllerDelegate
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController!, ontoPrimaryViewController primaryViewController: UIViewController!) -> Bool {
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool {
return collapseDetailViewController
}
}
```
~~~

~~~{objective-c}
@import UIKit;
@interface SelectColorTableViewController : UITableViewController <UISplitViewControllerDelegate>
@end
@interface SelectColorTableViewController ()
@property (nonatomic) BOOL shouldCollapseDetailViewController;
@end
@implementation SelectColorTableViewController
#pragma mark - UITableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// ...
self.shouldCollapseDetailViewController = true;
self.splitViewController.delegate = self;
}
// ...
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.shouldCollapseDetailViewController = false;
}
#pragma mark - UISplitViewControllerDelegate
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
return self.shouldCollapseDetailViewController;
}
@end
~~~

When the user first opens up the app on iPhone 6+ in portrait orientation, `SelectColorViewController` gets displayed as the primary view controller. Once the user selects a color or the app goes into the background, the `SelectColorViewController` gets collapsed again, and the `ColorViewController` is displayed:

Expand Down

0 comments on commit 0c45b6b

Please sign in to comment.