Aleksandar • Vacić

iOS bits and pieces

Masterclass: Code signing & Provisioning profiles

The voodoo.

The dark alley.

Never works.

Do not touch “Fix issues” ever, it will ruin everything!

I can list hundred more scary quotes that various iOS developers will tell you. And for years this was actually close to the truth, as Xcode’s integrated attempts to ease the management of the profiles were less than stellar.

This is extremely complicated and convoluted part of the iOS developer life. Apple recognizes this and Xcode and iTunes Connect / Developer Portal teams have worked for years to make this work seamlessly.

So next time when you are fed up with all the nonsense and just want to burn it all – go and do just that. Seriously, make a clean start.

Masterclass: Constants and Flags

You have probably seen something like this many times:

1
2
3
4
5
6
7
#define kMySegueIdentifier @"SegueMain"
#define reuseIdentifier @"TABLECELL"
#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 320.0f
#define CELL_CONTENT_MARGIN 10.0f

CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

This is usually found in quick&dirty code samples, to define constants. You can also see it in many older APIs, where various constants were defined this way. This is bad. It works, but it’s lazy.

#define is pre-processor directive and should not be used to define numbers and strings that will then be used as part of the actual code. It’s a hard-coded value that lives in its own memory space, outside of your regular scope.

Use proper, modern stuff that Objective-C offers and Xcode supports very well.

Masterclass: naming things

I’m a big believer that code should have consistent style. I got my first contract web gig not by how my code performed, but how it looked. Its vibe was that it’s a code done by person that cares.

There is only one true rule: make up your mind and be utterly and thoroughly consistent.

Style guide

I was lucky to be properly schooled very early on naming and general guidelines how Cocoa code should look. I found two great blog posts by Scott Stevenson (he works at Apple for a number of years now) from back in 2004. Everything he wrote back then still holds true and I urge you to go and read both. Scott explains not only how but also why it should be that way.

Back in 2008, I made a small booklet out of those pages and color-printed it. It was siting on my table for years, right next to the monitor.

Over time, I have developed few rules of my own.

How to invalidate flow collection view layout on rotation

Say you want to have grid layout with cells always half the size of the screen’s width. You want to maintain that layout in both portrait and landscape. Since iOS 8 that can’t be easier, with the right incantations.

First, subclass UICollectionViewFlowLayout.

Then add the following method into it:

1
2
3
4
5
6
7
8
9
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds {

  UICollectionViewFlowLayoutInvalidationContext *context = (UICollectionViewFlowLayoutInvalidationContext *)[super invalidationContextForBoundsChange:newBounds];
  context.invalidateFlowLayoutDelegateMetrics = (
                                                 CGRectGetWidth(newBounds) != CGRectGetWidth(self.collectionView.bounds) ||
                                                 CGRectGetHeight(newBounds) != CGRectGetHeight(self.collectionView.bounds)
                                                 );
  return context;
}

The key here is casting returned context from super as UICollectionViewFlowLayoutInvalidationContext which allows you to toggle the invalidateFlowLayoutDelegateMetrics property. That will tell UIKit that it should re-query FlowLayout’s delegate for the sizes.

In the collection view controller, make sure it’s set to adopt UICollectionViewDelegateFlowLayout protocol and then add this delegate call:

1
2
3
4
5
6
- (CGSize)collectionView:(UICollectionView *)collectionView
                layout:(UICollectionViewFlowLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

  return CGSizeMake(floor(self.view.bounds.size.width/2.0), 88);
}

Done.