By: Comments Off

iOS Concept Designs

Here is yet another iOS 7 concept video. I want to talk about it a little bit, so give it a watch (mute your speakers first).

Here's the thing: iOS doesn't need a lot of what this designer is showing off. Quick access to bluetooth settings and airplane mode? No one needs quick access to airplane mode. Widgets? Please. Double-tapping home screen icons is a terribad idea.

Don't get me wrong – it's a well-done video and the designer presents some intriguing ideas, but I can't help but feel like they didn't think a lot of these things through past the "oh this would look cool" phase.

For example, has the designer thought about what double-tapping home screen icons would imply, technologically? The OS would need to pause after every single-tap to make sure you aren't about to double-tap, delaying every app launch by a half second and slowing down the apparent responsiveness of the OS. Is that worth having widgets?

Several of the tap targets I noticed throughout the video look far too small. Controls should have a size of at least 44x44 points to provide a visual affordance to the user that they can be tapped.

Design doesn't exist in a vacuum. Think about how your design is going to fit within the technological ecosystem that it'll live in.

Don't get me wrong – iOS is not perfect. It has a lot of room to grow and is even being surpassed in some ways by other mobile operating systems. But don't go out and grab every feature from every OS you care to riff off – mobile and desktop – and call it a good concept video. Let's be sensible about what we're asking for from Apple, because who knows – we might end up with it.

/Ash Furrow /Comments Off
By: Source Comments Off

Springboard

I've launched a new podcast: Springboard. It's a show for newcomers to iOS software development.

My inaugural guest is Matthew Bischoff. We had a great conversation about getting started with your first app, some awesome tips and tricks, and how to get featured by the App Store. Definitely subscribe and give it a listen.

/Ash Furrow /Comments Off
By: Comments Off

Software Accessibility Goes Beyond Screen Readers

Software accessibility is about more than just making software accessible to people who can't see. Visual impairments are common, so making software accessible to users using screen readers, like VoiceOver on iOS, is key. However, lots of other impairments exist and it's important to take that into consideration when designing your software.

Consider the scrolling indicator colour. When you're designing your mobile web site, Safari uses the background colour of the body tag to infer the colour of the scroll indicator (light or dark). If your body tag is light, but it's covered by a dark div, then the indicator is going to be dark – on top of a dark div. Users with visual impairments are going to have a hard time seeing the indicator, rendering the scroll indicator completely useless to them Furthermore, users with cognitive impairments aren't going to be able to rely on that visual affordance either, possibly confusing. Don't betray the user's expectations – it will only make them more likely to leave your site.

Part of making good software is making usable software. Software accessibility is just a specific form of usability. Keep that in mind the next time you build something.

/Ash Furrow /Comments Off
By: Comments Off

We Need to Grow

I'm over half way to my funding goal on my Indiegogo project to fund my next book. One of my primary goals in this project is to attract existing developers working with other languages and ecosystems into the iOS world. I believe that we are sitting at a crossroads between stagnation and evolution. We need diversification to continue growing.

Why?

I sit behind an iMac all day and I happily code iOS apps. It's all I know. I'm sure I'm not alone. We specialize in iOS because we want to be great at it.

The problem is, we sit a little too close. We lose perspective. We don't know the right kinds of questions to ask.

We need new developers with other perspectives in our community because they will ask the right kind of questions. For example, they'll ask "why doesn't Objective-C have a package manager?" And then they'll make one.

A more diverse iOS developer community will make us better by forcing us to re-evaluate our assumptions. Things change, especially in the tech world. If we want to keep from stagnating, it's incredibly important to constantly question everything we know.

But that's impossible to do on our own. We need the help of iOS newcomers to force us to ask the uncomfortable questions we don't want to know the answers to. As Shunryu Suzuki wrote, "In the beginner's mind there are many possibilities, in the expert's mind there are few."

We'll get better tools. We'll get broader perspectives. We'll grow instead of dying.

Sounds good to me.

This project isn't just a book – it's a tool for making us better. Please help spread the word.

/Ash Furrow /Comments Off
By: Source Comments Off

5 Things to Know When Designing for iOS

For my first contribution to the Teehan+Lax Blog, we have 5 Things to Know When Designing for iOS.

Well, they also aren’t using a mouse. Instead, all interactions with your app are made with a far less precise instrument: a finger.

I had fun with this one.

/Ash Furrow /Comments Off
By: Comments Off

iOS and Objective-C for Beginners

My friend Andrey helped me record this video for my Indiegogo campaign. Check it out.

I've been overwhelmed by the response online. In only a few days, we're 30% of the way to my goal.

This isn't just about writing a book. This is about providing a community resource to help make us all better at what we do. This is going to be awesome.

/Ash Furrow /Comments Off
By: Comments Off

Crowdfunding my Next Book

I've decided to crowdfund my next book on Indigogo and I'm super pumped!

It's going to be an in-depth, ground-up book on writing your first iOS app. I've had this book on my mind since last September and I'm finally ready to begin work.

Sample code is going to be available on GitHub. Backers at the "Assistant Editor" level are going to get early access to the code and chapters via GitHub.

Go back me!

/Ash Furrow /Comments Off
By: Comments Off

Doom CPU Monitor

My friend Tom Creigton and I threw together a small little OS X app that monitors your CPU. The more you're pushing your processor, the bloodier the guy from the Doom video game gets.

/Ash Furrow /Comments Off
By: Comments Off

Fixing Xcode Brace Behaviour

My friend Zev maintains a great library for fixing Xcode's code snippets behaviour to put new brace brackets on their own line.

He's also got a section of his .zprofile in a gist so he can type fixXcode and it'll clone the repo and do everything for you. Like magic.

He sent it to be, and I was hesitant at first because it involves using zsh instead of bash. I mean, only nerds use zsh right?

Right!

zsh has autocomplete for git. That is all you need to know to switch.

/Ash Furrow /Comments Off
By: Comments Off

Putting a UICollectionView in a UITableViewCell

So you want to put a collection view inside of a table view cell, eh? Sounds easy, right? Well, to do it right requires a little bit of work. We want a clear separation of concerns so that the UITableViewCell isn't acting as the data source or delegate for the UICollectionView (because that would be very, very bad). You can follow along by downloading the sample code.

We're going to build a view hierarchy like the one below. Each UITableViewCell will contain a UICollectionView instead in its contentView. (For reasons we'll get into momentarily, this collection view needs to be a custom subclass.) Each collection view contains a certain number of cells, defined by its datasource.

Each collection view will have the same data source and delegate as the table view, necessitating the requirement to use a custom UICollectionView subclass.

The diagram should show you that the tricky part here is going to be getting the UICollectionView to see the view controller as the delegate. That's fine, we'll just subclass UICollectionView to get it to have an index property. Subclassing UICollectionView isn't common, but it's perfectly acceptable here.

Adding the collection view to the cell is very strait forward. We'll create an instance of AFCollectionView using a standard UICollectionViewFlowLayout in our cell's designated initializer.

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;

    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
    layout.itemSize = CGSizeMake(44, 44);
    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.collectionView = [[AFIndexedCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CollectionViewCellIdentifier];
    self.collectionView.backgroundColor = [UIColor whiteColor];
    self.collectionView.showsHorizontalScrollIndicator = NO;
    [self.contentView addSubview:self.collectionView];

    return self;
}

We'll adjust the side of the collection view to fill the cell in layoutSubviews.

-(void)layoutSubviews
{
    [super layoutSubviews];

    self.collectionView.frame = self.contentView.bounds;
}

Next, we'll set up our model in the view controller. We'll use UIColors because they're easy. Each cell will display a different, random colour.

This model is going to represent the table view and each collection view. We'll use an array; each object represents a table cell. These objects are themselves arrays, with each of their objects representing a collection view cell.

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.colorArray.count;
}

Next we'll implement our UICollectionViewDataSource methods.

-(NSInteger)collectionView:(AFIndexedCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    NSArray *collectionViewArray = self.colorArray[collectionView.index];
    return collectionViewArray.count;
}

-(UICollectionViewCell *)collectionView:(AFIndexedCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{    
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CollectionViewCellIdentifier forIndexPath:indexPath];

    NSArray *collectionViewArray = self.colorArray[collectionView.index];
    cell.backgroundColor = collectionViewArray[indexPath.item];

    return cell;
}

You'll see we're using the index property of the collection view to determine the appropriate model to use. Notice that the view controller doesn't retain references to any of the collection views – they belong to the UITableViewCells only. This is great, since they'll be re-used and save memory.

But where is the index getting set? We'll need to do that, too.

-(void)tableView:(UITableView *)tableView willDisplayCell:(AFTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setCollectionViewDataSourceDelegate:self index:indexPath.row];
}

The only thing left to do is "remember" the content offset of each cell as we end displaying it to reset it when we begin displaying it again. I we don't do this, newly displayed collection views will have non-zero content offsets and returning collection views will be in different positions. We'll use an NSMutableDictionary to remember the content offsets.

-(void)tableView:(UITableView *)tableView willDisplayCell:(AFTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setCollectionViewDataSourceDelegate:self index:indexPath.row];
    NSInteger index = cell.collectionView.index;

    CGFloat horizontalOffset = [self.contentOffsetDictionary[[@(index) stringValue]] floatValue];
    [cell.collectionView setContentOffset:CGPointMake(horizontalOffset, 0)];
}

-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(AFTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    CGFloat horizontalOffset = cell.collectionView.contentOffset.x;
    NSInteger index = cell.collectionView.index;
    self.contentOffsetDictionary[[@(index) stringValue]] = 
        @(horizontalOffset);
}

That's it. Not a lot of code, but to do it right, it requires a little bit of planning ahead. You can download the entire sample code on GitHub.

If you've enjoyed this tutorial, and I sincerely hope you have, then I'd recommend my ebook, UICollectionView: The Complete Guide. In the book, I go into far more detail on every aspect of using UICollectionView. You can pre-order it now and get access to all the draft chapters immediately.

/Ash Furrow /Comments Off