Swift 3 is a reevaluation of the past 2 years and changes a lot from previous versions

Guidelines
SE-0023
https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

Principles
– Clarity is more important than brevity on the code

Strive for clear usage, omit needless Words

From:
Too vague
friends.removeItem(ted)
friends.removeObject(ted)
friends.removeElement(ted)

And
Too specific
friends.removePerson(ted)
views.removeViews(myView)

Too
Removing needless words, if a word is not contriuting to the clarity of a usage, remove it
friends.remove(ted)
views.remove(myView)

Getting towards to having clear code that is concise

What words are needed?
myView.addChild(view, atPoint:origin)

The specification of Child is important, as it gives the context of hierarchy for the parameter

myView.addChild(view, atPoint:origin)

Since the method already gives a strong type for the parameter, the method can only recieve CGPoint, so there is no need to respecify that we are passing a point via paramter. It doens’t give additional information.

myView.addChild(view, at:origin)

 

Claryfying the behaviour of the api
By adding
friends.remove(ted) remove(_:)
friends.remove(at: formerFriendPosition) remove(at:)

In swift a method is comprised by base name “remove” as well as the argument labels. Both methods are in the same method family and they specify via the paremeter label.

In Swift you can overload methods, only if it is essentially the same operation only overloaded with different types:
text.append(aCharacter) // append(_:)
text.append(aString)

Examples where to add a parameter label, as general rule, when it helps to read well gramatically:
truck.removeBoxes(withLabel: "A label")
viewController.dismiss(animated: true)
friends.insert(michael, at: friends.startIndex)

Mutating vs non-Mutating
The “ed/ing” rule
x.reverse() //mutating
let y = x.reversed() //nonmutating

documentDirectory.appendPathComponent(".list") // mutating
let documentFile = documentDirectory.appendingPathComponent(".list") //non mutating

New API/Two Names
One name that is appropiate for Objective-C and one for Swift

Objective-C “Stringly typed” method names
in Swift 2.2:
controller.addTarget(self, action: #selector(handleDrag(sender:for)))

New in Swift 3:
Setters:
self.perform(#selector(setter: Artist.name))

Keypaths (Pound keypaths)
instead of:
album.addObserver(self, forKeyPath:"artist.name")
now:
album.addObserver(self, forKeyPath:#keypath(Album.artist.name))
Compiler validates that are Objective-c properties produces the name to pass it down to the frameworks

For mixed projects (Obj-C + Swift) some namings might not be good for one or another language

Swift
extension MyController{

@objc(handleDrag:forEvent:)
func handleDrag(sender: UIController, for event: UIEvent){} //handleDrag(sender:for) doesn’t make to much sense for Objective-c, use annotation to specify the objective-c name
}

Generated Objective-C from above

@interface MyController()
- (void)handleDragWithSender:(UIControl *)sender for:(UIEvent *)event;
@end

Translate to Swifty APIs
Automatic translations with Swift compiler
1) inspects method names and use gramatic queues to infer first parameter labels
e.g:
func saveToURL(_ url:String)
func save(toURL url:NSURL)

2) inspects names to remove reduntant information
func save(toURL url:String, forSaveOperation saveOperation: UIDocumentSaveOperation)
func save(to url:NSURL, for saveOperation:UIDocumentSaveOperation)

3) Infer default values for common objective-c idioms, like completionHandlers or option sets
func save(to url:NSURL, for saveOperation:UIDocumentSaveOperation, comletionHandler: ((Bool) -> Void)? = nil)

4) New bridging value types like URL that bridge the Objective-C Objects
func save(to url:URL, for saveOperation:UIDocumentSaveOperation, comletionHandler: ((Bool) -> Void)? = nil)

Translate “stringly” typed API to swifty (ish) API
NS_EXTENSIBLE_STRING_ENUM to transform stringly typed objective to swift
e.g
NSString *NSCalendarIdentifierGregorian = "gregorian"
to
Objective-C
typedef NSString *NSCalendarIdentifier NS_EXTENSIBLE_STRING_ENUM
NSCalendarIdentifier NSCalendarIdentifierGregorian;

Generated Swift
Transformed to Strongly typed
struct NSCalendarIdentifier: RawRepresentable{
init(_ rawValue:String)
var rawValue: String{ get }
static let gregorian:NSCalendarIdentifier
}

use
let cal = NSCalendar(identifier: .gregorian)

with bridge
let cal = Calendar(identifier: .gregorian)

Translate C API into Swifty API
NS_SWIFT_NAME import globals as members of type

C
CFStringRef kCGColorWhite NS_SWIFT_NAME(CGColor.white)
Generated Swift
extension CGColor{ static let white:CFString }
Swift use
let color = CGColor.white

C
CGAffineTransform CGAffineTranformMakeTranslation(CGFloat tx, CGFloat ty) NS_SWIFT_NAME(CGAffineTransform.init(translationX:y:));
Generated Swift
extension CGAffineTransform{ init(translationX: CGFloat, y: CGFloat) }
use
let translat = CGAffineTransform(translationX: 1.0, y: 0.5)

Complete example:

From this:

Screen Shot 2016-06-15 at 17.17.42

 

To this:

Screen Shot 2016-06-15 at 17.17.29

 

Having problems with your migration of Parse Database to your own MongoDB?

Not very elegant but it works… You can export your data manually from Parse App > App Settings > General Export data. You’ll get the .zip export, run manually the mongodbimport command pointing to your database. But you need to adjust the json files, remove the “results” key and leave it as an array. Then execute this command in your terminal (do not connect to your db):

mongoimport -h [mongo-db] -d parse -c [class-name] -u [user] -p [password] --file [path-to-json-file] --jsonArray

Downside: User sessions can’t be exported, so user is unable to login, but works fine in early stage if you can let the user register again

First thing, the setup I am using to not get error:

timed out waiting 120 seconds for simulator to boot

Before Integration Script:
open -b com.apple.iphonesimulator

After Integration Script:
xcrun simctl shutdown booted
xcrun simctl erase all
killall "Simulator"

A bit of background:
The app I am developing has a sync process that begins right away as soon as the app is installed for the very first time (and subsequently each 24h). This first time the app runs, it stores in Keychain the credentials, so Login screen will never show up again in any future sync processes.

I am integrating now KIF integration tests and I want to run them on a Bot with XCode Server on an OSX Server.

I have built a test that does this sync process: waits for a notification, waits for login screen, enters credentials, clicks login, waits for notification when sync process is finished.

The first time this runs with the XCode Server bot, it works perfectly. But on the next ones, the app has already all the data and has already the credentials stored in Keychain, so this test would fail since none of the notification would be posted and the login screen would never appear.

Which means the simulator isn’t stateless, it has a state and a different one than the first time it is being launched.

To the point
Since I want to test this first sync process and don’t want to add if statements in my tests, I want to reset the Contents and Settings of the Simulator, before or after each continuous integration.

I have tried to trigger scripts before with:
xcrun simctl erase

But I was getting this error
Unable to erase contents and settings in current state: Booted

Then I added
xcrun simctl shutdown booted

But then the server wasn’t able to boot it. So I tried to boot it with the boot command but, it didn’t work. So I decided to try to clean after.

So now the after trigger script looked like this:

xcrun simctl shutdown booted
xcrun simctl erase all

Then I began to get the famous error
timed out waiting 120 seconds for simulator to boot

With all those tests and errors I was getting, the server always went into an inconsistent state, so I had to restart my machine to being able to test again.

Since the cleaning after wasn’t working, but still made sense to me. I ran the 2 line script, on my terminal on my machine with my user (not the server), and there the simulator went also into an inconsistent state. In the means of, it erased everything, but it didn’t look like it because it still was open and the app still seemed to be installed, until I restarted manually the simulator, then the app was gone.

So I thought, could be happening the same with the simulator on the server. This blog post http://joshuabrauer.com/2015/04/xcode-server-and-continuous-integration-ios gave me the hint to access with the server user.

Changed the password and just log in my computer as _xcsbuildd, with my new password. It might ask to add a new entry in the Keychain since I didn’t know the previous password.
There I saw the open simulator with the installed app.

————
By the way, it was quite some time before I realized that the simulator I was using for running my app, wasn’t the same as the one the server was using. My reasoning was, if the server is asking me what xcode it should use, why doesn’t it use the same simulator. Actually it seems that uses the same simulator, but different path for the device folders.
Anyway I got it when I saw the logs of the bot, the list of available devices inside a mysterious unaccessible _xcsbuildd folder.
————

I added
killall "Simulator"
To the after script.

This one seemed to be working, that way I wasn’t getting anymore error
timed out waiting 120 seconds for simulator to boot

But now I am getting error:

Assertion: Lost connection to test manager service

So I thought it might be because it can’t boot it, so I added a before trigger to force the boot.
open -b com.apple.iphonesimulator

So far it is being stable, but I am still testing. I am still getting sometimes the
Assertion: Lost connection to test manager service
error but, as I said, I am still finding it out. I might add a sleep after the booting of the simulator to give it time, hopefully that solves it.

Overall the feeling is that all this setup of Apple is not very stable, and finding out the issues is hard since it takes long and previous issues might be influencing good solutions.

Just google
timed out waiting 120 seconds for simulator to boot
and you’ll see so many entries of people getting this error and everybody trying different things.

A few weeks ago I published my first contribution to CocoaPods. It is a library to draw line graphs on a plot.

I wanted something really easy to use, where you just drop some values and the library does the rest. Calculates nice axis values, functionality for logarithmic plot, linear plot, value changes animated or not, dashed/dotted/solid lines, filled or not, etc.

All this in a very “Apple style” library, with delegates asking optionally anything that could be customised. Another important thing to me was, that it should be able to work with nib files as well as views created by code and Auto-layout.

See video: Not a very “designish” example of what can be done, but it shows all functionality. On the previous post you’ll see a much nicer version of it.

Gif:
graphs

Please check it out at github, fork it, tweak it, comment it, would be nice to see it grow!
There is still work to do on it. Adding tests, more functionalities, etc.

In CocoaPods

And to finish just a note about CocoaPods and their great work, it was really ease to follow the steps with their awesome guides

I come across an issue as I have wanted to draw lines in a grid format. My first approach, drawing a UIBezierPath in a CAShapeLayer.

My issue is the resultant fuzziness on the lines, as they need to be located in floating values. Which makes actually sense that the lines are fuzzy. What I didn’t expect is that, if I use UIViews and position them on the exact same points as the Bezier points, I don’t get this fuzziness (see screenshot. UIView must be doing this correction somehow, don’t remember if in AS3 this was the case… but I am pretty sure even Views had to be on the integer value to avoid this.

graphs

I most likely will get the same result as the UIView, rounding up or down the floating values.

Refactoring helps you develop code more quickly

Refactoring is something you do all the time in little bursts. You don’t decide to refactor, you refactor because you want to do something else, and refactoring helps you do that other thing.

The Rule of Three
The third time you do something similar, your refactor

Refactor when you add a function/feature
Whenever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent.

Thoughts
Overall:
A nice read to enforce your conviction to use Refactoring

Refactoring Design
In Chapter 2 Refactoring seems to be presented as a solution to thinking the upfront “best design”, kind of like if it was the perfect detergent for a stain.

What I think the use of Refactoring is kind of a natural evolution of a developer. As beginners we stress out on our first architecture /design, then you evolve a bit and consider that sometimes it is easier to just begin developing instead of sitting for weeks in front of blank paper, yes you might get stuck with the crappy first design on this project. But on the next step you will be almost Refactoring without doing a conscious exercise.
And then learn techniques to refactor

By: Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts

Chapter 1:
Decomposing and redistributing methods:
– locate modified local variables, if there is only one, extract it to a separate method and return it.
– A method should be on the object whose data it uses. E.g: “amount calculation only uses information of the Rental, methods should not be under Customer but under Rental”
– local/temp/auxiliar variables are often a problem in that they cause a lot of parameters to be passed around when they don’t have to be. Easily lose track of what they are there for.
– Get rid of local variables that are assigned as result of an extracted/refactored method. Performance might be affected, but that is another step outside the refactoring process. Optimisation is much easier done with a refactored code.
– Replace temp/local variables with “Query”-> replace with private helper methods (which could end up being public easily)
– Replace conditional logic with Polymorphism. “It is a bad idea to do a switch based on an attribute of another object. If you must use a switch statement, it should be on your own data, not on someone else’s”
– If inheritance is not an option, you need the object to change class during its lifetime (New Release Movie can change to Regular Movie during the lifetime) -> Strategy or State pattern.
– Strategy or State pattern a very similar, to differentiate them ask question: Does the class represent an algorithm for calculating or does it represent a state?.

Strategy pattern – Wikipedia:

enables an algorithm’s behavior to be selected at runtime
– defines a family of algorithms,
– encapsulates each algorithm, and
– makes the algorithms interchangeable within that family.
For instance, a class that performs validation on incoming data may use a strategy pattern to select a validation algorithm based on the type of data, the source of the data, user choice, or other discriminating factors. These factors are not known for each case until run-time, and may require radically different validation to be performed.

WWDC 2012 V202

Add the constraint to the two views closest ancestors, every view is considered an acestor of itself.
E.g:
– Two siblings, add constraint to parent view.
– Cousins, constraint to grand parent

viewDidLoad – good place where to set the constraints

po [[UIWindow keywindo] _autolayoutTrace] to visualize the AutoLayout

setTranslatesAutorezingingMaskIntoConstraints -> If not using Auto Layout, Springs and masks are translated into AutoLayout.

WWDC 2012 V228
For debugging:
knowing what constraint is affecting
[view constraintsAffectingLayoutForAxis: NSLayoutCosntraintOrientationHorizontal/Vertical]

[view exerciseAmbiguitiInLayout]

Animation can be applied to the view or to the Auto Layout property

CoreAnimation:
1) Adjust constraints
2) [UIView animateWithDuration: 0.5 animations:^{
[view layoutIfNeeded];
}];

NSLayoutContraint:
changing the constant of a NSLayoutConstraint permits efficient relayouts
on iOS this can only be animated with NSTimer and on tick changing constraint.constant value

Alignment Rect:
Used to calculate the bounds to algin,doesn’t need to be the frame

Intrisinsic Content Size
Equivalency with sizeToFit, sizeThatFits
It is a preferred size, is not settable, constraint set them with their priorities

Any time the content changes so that the intrinsic content size should change-> [self invalidateIntrinsicContext]
Use intrinsicContentSize as a better sizeToFit
NSRect alignmentRect = (NSRect) {NSZeroPoint, [control intrinsicContentSize]};
[control setFrameSize: [control frameForAlignmentRect:alignmentRect].size];

Localisation
RTL
AutoLayout uses leading and trainling and they flip automatically on

WWDC 2012 V232 Autolayout By Example

Arguments:
NSDoubleLocalizedStrings YES: Multiplies all the strings by two to debug the Layout
Simulate right to left
AppleTextDirection YES
NSForceRightToLeftWritingDirection YES

Draw view alignment rects
UIViewShowAlignmentRects YES

Localizing RTL
If an asset is not desired to flip on language change… In IB set direction instead to Leading to Trailing, to the specific direction

2012 V244 Internationalization Tips and Tricks

NSLocale
+ currentLocale: returns static object that doesn’t change
+ autoupdatingCurrentLocale: picks up any changes to dateformat settings, time to show in 12h format, etc.
NSCurrentLocaleDidChangeNotification: when the settings change, received this notification the UI should update to new locale

Localising Text
Generating Strings entries from source files
find . -name \*.m | xargs genstrings -o en.lproj/

Searches for NSLocalizedString(@”key”, @”description”) and translates to:
/* description */
“key” = “key”

Sorting
instead of -compare: use -localizedStandardCompare:

Searching
avoid -[NSString rangeOfString:] does not take into account user local it uses system local.
use -[NSString rangeOfString:options:range:locale:] passing currentLocale or the autoUpdatingCurrentLocale

Directionality
Arabic being RTL can contain LTR text e.g: Brand names
Visually text is shown RTL but when the string is stored in memory it is stored in a single logical order LTR. When searching through string character by character or word by word. This directionality needs to be taken in consideration

Parsing
Not all characters fit in a unichar. Affects when using methods like character at index.
Avoid:
-characterAtIndex:
-length
-precomposedStringWithCanonicalMapping

Use:
-enumerateSubstringsInRange:options:usingBlock:

Custom Macros
ITTRootViewControllerString(@"key", @"description");
NSString* ITTRootViewControllerSTring(NSString *key, NSString *comment){
NSBundle *b = [NSBundle mainBundle];
NSString *str = [b localizedStringForKey:key value:nil table:@"ITTRootViewController"];
#if DEBUG
str = ITTPseudolocalize(str);
#endif
return str;
}

Pseudolocalize: Rewrite the string with any type of mark to be sure the text has been localised e.g: My lovely label -> $$My lovely label$$

Date
easiest way to convert a date into a string:
+localizedStringFromDate:dateStyle:timeStyle:

Avoid:
NSDateFormatter *df
[df setDateFormat:@"M/dd/yyyy"];

this is correct only in some countries
Use:
[df setDateStyle:NSDateFormatterShortStyle];

If you only want to show the month of a date:
Avoid:
[df setDateFormat:@"MMM d"];
Use:
NSString *format = [NSDateFormatter dateFormatFromTemplate:@"MMM d" options:0 locale:[NSLocale currentLocale]];
[df setDateFormat:format];

follows: Unicode Standard 35

Parsing Date String
Tell the dateformatter what calendar is being used. NSCalendar
strptime_l parse a timestamp to a time interval which can be formatted by the calendar

Timezones
Add timezone to the dateformatter: [df setTimeZone:[NSTimeZone timeZoneWithSecondsFromGMT:0]]

NSTimeZone: instead of being relative to a specific point in time it is relative to coordinated universal time.

NSDateComponents
Portions of a calendrical date, the various parts of the formatted human readable date

Unit lengths
- [NSCalendar maximumRangeOfUnit:] How many months
- [NSCalendar rangeOfUnit:inUnit:forDate:] how many days are in that month

AM/PM
Use @”j” for formatting an hour
[NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]];

US: h a (1-12 am)
Japan: H (0-23 withouth am)
France: HH (00-23 without am)
China: ah (am before 1-12)

Localizing Numbers
NSNumberFormatter
+localizedStringFromNumber:numberStyle

Parsing Numbers
Avoid
-intValue, scanf, etc
Use
NSNumberFormatter *nf
[nf setNumberStyle:NSNumberFormatterDecimalStyle];

Avoid
+stringWithFormat:, printf, etc
Use
[NSNumberFormatter localizedStringFromNumber:myNumber numberSTyle:setNumberStyle:NSNumberFormatterDecimalStyle];
Will use the correct character set for arabic

Currency
[nf setNumberStyle:NSNumberFormatterCurrencyStyle];

No unit conversion but NSLocale can tell you what currency/unit should be used
Unlocalized numbers strto*_l for the same purposes as the NSCalendar

Images
[UIImage imageNamed]; Uses NSBundle and this one takes the language into account

2013 V219 Making Your App World-Ready

Use Base Internationalization
– Edit only one set of nib files
– String file is generated for each storyboard and nib file
– localizers only need to edit the strings file
– use autolayout with base internationalization

ibtool generates a strings file for you. When a nib file has changed, inside the Base.lproj folder:
ibtool ChangeNib.xib –generate-strings-file NewStrings.strings

New in iOS7
stringsdict to take into account plurality and/or gender
Localized propertylist:
result = [NSString localizedStringWithFormat:NSLocalizedString(@”%d file(s) remaining”, @”comment”, n] -> research more on this check foundation release notes and What’s new in Cocoa WWDC 2013

Testing
Run the app with the argument
-AppleLanguages "(Korean)"

NSDataDetector to detect phone numbers, Addresses, make them into links

2014 V201 Advanced topics in internationalization
Language and Region Settings
– Primary language
– Specify preferred languages in order
– User can specify preferred language although it isn’t available in the OS but your app can be localised with that language
– Specify the region independently of the localization

iOS8 – when the text encoding type is not provided it can be abled to guess with the API
+ (NSStringEncoding) stringEncodingFromData:(NSData *)data
encodingOptions:(NSDictionary *)opts
convertedString:(NSString **)string
usedLossyConversion:(BOOL *)usedLossyConversion

iOS8 – NSDateComponentsFormatter
For displaying duration or amounts of time (1 hour, 50 minutes)

iOS8 – NSDateIntervalFormatter
For displaying time intervals (9:00 AM – 4:30 PM)

iOS8 – NSEnergyFormatter, NSLengthFormatter, NSMassFormatter

iOS8 – Formatting Context
Tells how the formatted text should be written, depending on how and where it appears:
– NSFormattingContextStandAlone
– NSFormattingContextListItem
– NSFormattingContextBeginningOfSentence
– NSFormattingContextMiddleOfSentence
– NSFormattingContextDynamic, once it is inserted in the formatted string it resolves beginning, middle of sentence.

Tip
In case you need to know the language the app is running because you want to show something running in Japanese but not in english. Put a localised resource in the NSBundle with value YES or NO on the required resource

Locale Change eg
- (void userChangeLocale: (NSNotification *) notification{
myFormatter.locale = [NSLocale currentLocale];
myFormatter.dateFormat = [NSDateFormatter dateFormatFromTemplate: myTemplate option:0 locale:myFormatter.locale]

[myView setNeedsDisplay];
}

Names
Don’t assume “First Last”
Avoid
NSString *displayName = [NSString stringWithFormat:@"%@ %@", firstName, lastname];
Use when used with Addressbook
NSString *diplayName= (NSString *) ABRecordCopyCompositeName(record);
When not form the Addressbook
ABRecordRef record = ABPersonCreate();
ABRecordSetValue(record, kABPersonFirstNameProperty, (CFStringRef) firstName, NULL);
ABRecordSetValue(record, kABPersonLastNameProperty, (CFStringRef)lastName, NULL);
NSString *displayname = (NSString *)ABRecordCopyCompositeName(record);
CFRelease(record);

Right-To-left
Avoid:
[textView setAlignment:NSTextAlignmentLeft]
Use:
[textView setAlignment:NSTextAlignmentNatural]

Text Directionality
Avoid:
[textField setBaseWritingDirection: NSWritingDirectionRightToLeft forRange:range];
Use:
[textField setBaseWritingDriection: NSWritingDirectionNatural forRange:range];
This guesses the directionality of the text, analyses the first characters and decides the direction.
In case this can not be used, because text is actually in arabic but begins with LTR letter: need to insert invisible character/mark that indicates the direction:
LRM: U+200E
RLM: U+200F

ios 6
In Scheme->Options->Aplication Language -> Right to Left Pseudo-Language

Keyboard
To make Keyboard and other UI Elements move in tandem, informatino we have:
Frame
UIKeyboardFrameBeginUserInfoKey
UIKeyboardFrameEndUserInfoKey
Animatin
UIKeyboardAnimationCurveUserInfoKey
UIKeyboardAnimationDurationUserInfoKey

Specify KeyboardType as not all Locales are going to show the same characters

Some localizations like chinese, the user types in the phonetic representations, the predictable text shows the options and then the user selects the correct option. This is indicated with -markedTextRange if it exists most likely the live search or similar won’t work as the typed in text is not the final text the user wants to input.

2014 V201 Localising with Xcode6
Export/import xliff format
Preview localizations

Recap for project
– use comments on NSLocalizedString
– use a different strings file per ViewController/Screen
– Pseudolocalize with macros
– use .stringsdict for plurals and gender control good resource http://www.objc.io/issue-9/string-localization.html
– listen to localeDidChange notification or use +[NSLocale autoupdatingCurrentLocale]. What should be done:
1)Listen to NSCurrentLocaleDidChangeNotification
2) If you keep formatters/locales around, use +[NSLocale autoupdatingCurentLocale]
3) Redo template formats
4) Invalidate any active views that contain locale-derived information
– ABRecordRef to display names
– Right-To-Left use: [textView setAlignment:NSTextAlignmentNatural]
– Directionality use: [textField setBAseWritingDriection: NSWritingDirectionNatural forRange:range]; With LRM/RLM marks

To use Dynamic Type in custom labels:
use preferedFontForTextStyle

iOS 8 CellSizing
First the tableview uses an estimated cell size. Once the cell needs to be displayed in screen:
1) Create Cell
2) Size cell
3) Update contentsize
4) Display cell

Self-sizing Cells
– Using Autolayout, if constraints are determined unambiguously nothing needs to be done, the autolayout engine returns back the correct size.

or

– Manual-sizing: override -sizeThatFits:

Autolayout:
– use tableView.estimatedRowHeight instead of rowHeight
– If tableView comes from nib file or story board. RowHeight will be set when it comes out of the nib so you need to set: tableView.rowHeight = UITableViewAutomaticDimension. this is the new default rowHeight.

Differences with iOS 7 on Dynamic sizing for Cells
iOS7
rowHeightForCellAtIndexPath:
This was called for ALL the cells on creation of the table view. So if we have 22000 cells to display this was called that many times. Cell size was difficult to provide, as the cell wasn’t created yet.

iOS8
Works with estimated cell height, once the cell is about to be displayed on screen then the real size is calculated and can even be retrieved automatically from AutoLayout.

Self-sizing Cells in CollectionView FlowLayout
Very similar to table view using size instead of only height.
estimatedItemSize instead of itemSize.

High-performance Layouts
iOS7 introduced invalidation contexts. Flow layout uses this for rotation, in iOS 8 used for self-sizing cells

iOS 8 improves on:
– floating headers
– avoid visual jumps with self-sizing cells

TODO: Research more about Invalidation contexts