153
iOS 9.0 This article summarizes the key developer-related features introduced in iOS 9, which runs on currently shipping iOS devices. The article also lists the documents that describe new features in more detail. For late-breaking news and information about known issues, see iOS 9 Release Notes . For the complete list of new APIs added in iOS 9, see iOS 9.0 API Diffs . For more information on new devices, see iOS Device Compatibility Reference . Multitasking Enhancements for iPad iOS 9 enhances the user’s multitasking experience on iPad with Slide Over, Split View, and Picture in Picture. The Slide Over feature lets users pick a secondary app and quickly interact with it. The Split View feature gives users the ability to use two apps side by side on iPad Air 2. The Picture in Picture feature (also known as PiP) lets users watch video in a window that floats above other onscreen apps. Users decide when they want to view two apps on the screen at the same time; you have no control over when this happens. Even though Split View and Slide Over are user-controlled, there are a few things you need to do to ensure that users have a great multitasking experience. It’s crucial that your app use system resources efficiently so that it can run well when it shares the system with another running app. Under memory pressure, the system preemptively quits the app that’s consuming the most memory. If you haven’t already, be sure to adopt size classes so that your app looks good when the user decides to view it in a portion of the device screen. To learn more about preparing your app to respond well when users use Split View and Slide Over, see Adopting Multitasking Enhancements on iPad . As with Split View and Slide Over, users control whether they want to use PiP to view a video on top of another running app. If video playback is not your app's primary functionality, there’s nothing you need to do to support the PiP experience. To participate when users choose Picture in Picture, use AVKit or AV Foundation APIs. The video playback classes defined in the Media Player framework are deprecated in iOS 9 and do not support PiP. To learn how to prepare your video playback app for PiP, see Picture in Picture Quick Start . Search App Search in iOS 9 gives users great new ways to access information inside of your app, even when it isn’t installed. When you adopt iOS 9 Search, users can access activities and content deep within your app through Handoff, Siri Reminders, and Search results. In addition to improving the user experience, adopting Search helps you increase the usage of your app and improve its discoverability by displaying your content when users search across the system and on the web. For an example of how this works, imagine that your app helps users handle minor medical conditions, such as a sunburn or a sprained ankle. When you adopt iOS 9 Search, users searching their devices for “sprained ankle” can get results for your app even when they don’t have your app installed. When users tap on a result for your app, they get the opportunity to download your app. Similarly, users can get results Page | 1

IOS - Concepts

Embed Size (px)

DESCRIPTION

Interview Concepts

Citation preview

iOS 9.0This article summarizes the key developer-related features introduced in iOS 9, which runs on currently shipping iOS devices. The article also lists the documents that describe new features in more detail.For late-breaking news and information about known issues, seeiOS 9 Release Notes. For the complete list of new APIs added in iOS 9, seeiOS 9.0 API Diffs. For more information on new devices, seeiOS Device Compatibility Reference.Multitasking Enhancements for iPadiOS 9 enhances the users multitasking experience on iPad with Slide Over, Split View, and Picture in Picture. The Slide Over feature lets users pick a secondary app and quickly interact with it. The Split View feature gives users the ability to use two apps side by side on iPad Air 2. The Picture in Picture feature (also known as PiP) lets users watch video in a window that floats above other onscreen apps.Users decide when they want to view two apps on the screen at the same time; you have no control over when this happens. Even though Split View and Slide Over are user-controlled, there are a few things you need to do to ensure that users have a great multitasking experience.Its crucial that your app use system resources efficiently so that it can run well when it shares the system with another running app. Under memory pressure, the system preemptively quits the app thats consuming the most memory.If you havent already, be sure to adopt size classes so that your app looks good when the user decides to view it in a portion of the device screen.To learn more about preparing your app to respond well when users use Split View and Slide Over, seeAdopting Multitasking Enhancements on iPad.As with Split View and Slide Over, users control whether they want to use PiP to view a video on top of another running app. If video playback is not your app's primary functionality, theres nothing you need to do to support the PiP experience.To participate when users choose Picture in Picture, use AVKit or AV Foundation APIs. The video playback classes defined in the Media Player framework are deprecated in iOS 9 and do not support PiP. To learn how to prepare your video playback app for PiP, seePicture in Picture Quick Start.SearchApp Search in iOS 9 gives users great new ways to access information inside of your app, even when it isnt installed. When you adopt iOS 9 Search, users can access activities and content deep within your app through Handoff, Siri Reminders, and Search results.In addition to improving the user experience, adopting Search helps you increase the usage of your app and improve its discoverability by displaying your content when users search across the system and on the web. For an example of how this works, imagine that your app helps users handle minor medical conditions, such as a sunburn or a sprained ankle. When you adopt iOS 9 Search, users searching their devices for sprained ankle can get results for your app even when they dont have your app installed. When users tap on a result for your app, they get the opportunity to download your app. Similarly, users can get results for your app and related web content when they search for sprained ankle in Safari. Tapping on a result in Safari takes users to your website, where they can download your app from your App Banner.Adopting iOS 9 Search is easy: You dont need any prior experience with implementing search, and most developers find that it takes only a few hours to make their content universally searchable. iOS 9 introduces the following APIs you can use to adopt Search:TheNSUserActivityclass includes new methods and properties that help you index activities and app states to make them available in search results. Just about every app can take advantage of theNSUserActivityAPIs to make useful content available to users. For more details, seeUse NSUserActivity APIs to Make App Activities Searchable.The new Core Spotlight framework (CoreSpotlight.framework) provides APIs that help you index the content in your app and enable deep links to that content. Core Spotlight is designed for apps that handle persistent user data, such as documents, photos, and other types of content created by or on behalf of users. To learn more about this framework, seeUse Core Spotlight APIs to Make App Content Searchable.Adding the appropriate web markup to your website makes your related web content searchable and helps you enrich the users search results. Adding a Smart App Banner gives users an easy way to link directly to your app. For more information about ways to make your web content searchable, seeUse Web Markup to Make Web Content Searchable. To learn how to use a Smart App Banner, seePromoting Apps with Smart App Banners.The three Search-related APIs are designed to work in concert. If you mirror app content on the web, you can adopt all three; apps that dont have related content on the web can adoptNSUserActivityand the Core Spotlight APIs.Adopting these APIs appropriately can improve the relevancy and ranking of the results related to your app. To give users the best search experience, the system measures how often users interact with app content and with Search and Safari results. iOS computes relevancy and ranking using information such as the frequency with which users interact with app activities, the time that passes between tapping a result and opening a deep link within your app, and (when appropriate) the reputation of your website.Important:Be sure to avoid over-indexing your app content or adding unrelated keywords and attributes in an attempt to improve the ranking of your results. Because iOS measures the level of user engagement with search results, items that users dont find useful are quickly identified and can eventually stop showing up in results.There are two main things you can do to ensure that users have a great experience when they search for content related to your app. First, make sure that your results are rich, descriptive, and useful. When users view compelling information thats directly related to their query, theyre much more likely to engage with your app. Second, when users tap a result, take them directly to the appropriate area in your app. As much as possible, avoid presenting intervening screens or experiences that delay users from reaching the content theyre interested in.Use NSUserActivity APIs to Make App Activities and States SearchableCurrently, you use theNSUserActivityAPI to support Handoff (to learn more about enabling Handoff in your app, seeHandoff Programming Guide). In iOS 9,NSUserActivityadds API that lets you designate specific activities or app states as searchable. When a searchable activity or state appears in Search or Safari results, users can tap the result to return to the relevant area in your app.NSUserActivityalso introduces properties you can use to provide indexable metadata about an activity or state, which helps you provide rich information in search results. For example, you can specify a title, description, and thumbnail image for a result.To make an app activity or state searchable, create anNSUserActivityobject to represent it. UseNSUserActivityproperties to fully describe the activity or state and to make it eligible for search.Listing 1shows how to set up an activity.Listing 1Creating a new activityNSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:@com.mycompany.activity-type];// Set properties that describe the activity and that can be used in search.userActivity.title = @"...";userActivity.keywords = [NSSet setWithArray:@[...]]; // Set values needed to restore stateuserActivity.userInfo = @{ };// Enable the activity to participate in search results.[userActivity.eligibleForSearch = YES];

When a user performs the activity or enters the app state associated with theNSUserActivityobject you created, your app calls[userActivity becomeCurrent]to mark the activity as current. A current activity thats eligible for search is automatically added to the universal index (that is,CSSearchableIndex).When a user taps on a result thats associated with an activity or state, your app usesNSUserActivityAPIs to continue the activity and restore the users position.Listing 2shows how to continue an activity.Listing 2Continuing an activity- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler: { NSString *activityType = userActivity.activityType; if ([activityType isEqual:@com.mycompany.activity-type]) { // Handle restoration for values provided in userInfo return YES; } return NO;}

In some cases, it's appropriate to make activities available to all users. For example, the Health app indexes its sections to make them available to all users. When a user searches for steps, Search lists an item that displays the users current steps; tapping the result automatically opens the Steps area of the Health Dashboard. Because steps is marked as a publicly searchable item, users who have never tracked their steps in the Health app also receive a link to the Steps area when they search for steps.An activity thats marked public can be shown to other users and can help encourage them to use your app. By default, activities are private. You should designate an activity as public only when the activity might be useful for other users. In general, user-created content is never useful for public results. To mark an activity as public, set theeligibleForPublicIndexingproperty toYES.Use Core Spotlight APIs to Make App Content SearchableCore Spotlight provides a database-like API that lets you add, retrieve, update, and delete items that represent searchable app content. When you use Core Spotlight to index items, you make it easy for users to search their own content.To make content searchable, first create an attribute set that contains properties that specify the metadata you want to display about an item in a search result. The attributes you choose depend on your domain. You can use the attributes that Core Spotlight provides in categories defined onCSSearchableItemAttributeSet, or you can define your own. If you want to define a custom attribute, be as specific as possible in your definition and use thecontentTypeTreeproperty (defined inCSSearchableItemAttributeSet_General.h) so that your custom attribute can inherit from a known type.Listing 3shows how to create aCSSearchableItemAttributeSetobject and set its properties.Listing 3Creating an attribute set for a searchable item// Create an attribute set for an item that represents an image.CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeImage];// Set properties that describe attributes of the item such as title, description, and image.attributeSet.title = @"";attributeSet.contentDescription = @"";Next, create aCSSearchableItemobject to represent the item and add it to the index.Listing 4shows how to create aCSSearchableItemobject and index it.Listing 4Creating a searchable item// Create a searchable item, specifying its ID, associated domain, and the attribute set you created earlier.CSSearchableItem *item;item = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"123456" domainIdentifier:@"domain1.subdomainA" attributeSet:attributeSet];// Index the item.[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:@[item] completionHandler: ^(NSError * __nullable error) {NSLog(@"Search item indexed");}];When users tap a search result for an item that you added to the index, your app should open and restore the context associated with that item. To accomplish this, your app delegate implementsapplication:continueUserActivity:restorationHandler:, checking the type of the incoming activity to see if the app is opening because the user tapped an indexed item in a search result.Listing 5shows a skeletal implementation ofapplication:continueUserActivity:restorationHandler:.Listing 5ImplementingcontinueUserActivityin the app delegate- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray *restorableObjects))restorationHandler { if ([[userActivity activityType] isEqualToString:CSSearchableItemActionType]) { // This activity represents an item indexed using Core Spotlight, so restore the context related to the unique identifier. // The unique identifier of the Core Spotlight item is set in the activitys userInfo for the key CSSearchableItemActivityIdentifier. NSString *uniqueIdentifier = [activity.userInfo objectForKey:CSSearchableItemActivityIdentifier]; }}Its recommended that you adopt bothNSUserActivityand Core Spotlight functionality if your app lets users create or store content. Adopting both APIs lets you create relationships between activities and items that represent the same thing, which improves the users experience.Listing 6shows how to use a unique ID to relate a user activity and an item.Listing 6Relating a user activity and a searchable item// Create an attribute set that specifies a related unique ID for a Core Spotlight item.CSSearchableItemAttributeSet *attributes = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:@"public.image"];attributes.relatedUniqueIdentifier = coreSpotlightUniqueIdentifier; // Use the attribute set to create an NSUserActivity that's related to a Core Spotlight item.NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:@com.mycompany.viewing-message];userActivity.contentAttributeSet = attributes;Core Spotlight provides several APIs you can use to work with the index and keep it up to date. Be sure to set theindexDelegateproperty in your app and implement the requiredCSSearchableIndexDelegate methods. For example,Listing 7shows how to batch updates to the index.Listing 7Batching updates to the indexCSSearchableIndex *index = [CSSearchableIndex new];[index beginIndexBatch];[index indexSearchableitems:items completionHandler:nil];[index deleteSearchableItemsWithIdentifiers:identifiers completionHandler:nil];[index endIndexBatchWithClientState:clientState completionHandler:^(NSError *error) { // Handle errors.}];If a crash occurs while youre batching index updates, use the value ofclientStateto help you recover, as shown inListing 8.Listing 8UsingclientStateto help you handle a crash while batchingCSSearchableIndex *index = [CSSearchableIndex new];[index fetchLastClientStateWithCompletionHandler:^(NSData *clientState, NSError *error) {

if(error == nil) { NSArray *items = // Fetch a batch of items for the specified client state. [index beginIndexBatch]; [index indexSearchableitems:items completionHandler:nil]; [index endIndexBatchWithClientState:clientState completionHandler:^(NSError *error) { // Handle errors. }]; }

}];Core Spotlight defines a few ways you can remove data from the index. For example,Listing 9shows different ways to specify items to delete from the index.

Listing 9Removing items from the index// Remove an item specified by identifier.[[CSSearchableIndex defaultSearchableIndex] deleteSearchableItemsWithIdentifiers:@[@123456] completionHandler:^(NSError *)error) { // Handle errors.})];CodeLine// Delete items in the specified domain and all subdomains.[[CSSearchableIndex defaultSearchableIndex] deleteSearchableItemsWithDomainIdentifiers:@[@domain1] completionHandler:^(NSError *)error) { // Handle errors.})];// Delete items in the specified subdomain.[[CSSearchableIndex defaultSearchableIndex] deleteSearchableItemsWithDomainIdentifiers:@[@domain1.subdomainA] completionHandler:^(NSError *)error) { // Handle errors.})]; // Delete all items.[[CSSearchableIndex defaultSearchableIndex] deleteAllSearchableItemsWithCompletionHandler:^(NSError *)error) { // Handle errors.})];In general, you should update the index while your app is running, but you can also create an index-maintenance app extension that lets the system communicate with your app while its not running and give you the opportunity to update the index or verify the validity of an item.Listing 10shows one way to write this type of app extension.Listing 10Creating an index-maintenance app extension@interface MyIndexRequestExtensionHandler : CSIndexExtensionRequestHandler @end @implementation MyIndexRequestExtensionHandler-(void)searchableIndex:(CSSearchableIndex*)searchableIndex reindexAllSearchableItemsWithAcknowledgementHandler:(void (^)(void))acknowledgementHandler { // Use index API to re-index all your data. // Call the acknowledgement handler when this is done.} -(void)searchableIndex:(CSSearchableIndex*)searchableIndex reindexSearchableItemsWithIdentifiers:(NSArray *)identifiers acknowledgementHandler:(void (^)(void))acknowledgementHandler { // Use index API to re-index data with the specified identifiers. // Call the acknowledgement handler when this is done.}@end

Use Web Markup to Make App Content SearchableIf you mirror your app content on a website (or your app gets all its content from a website), you can use web markup to give users access to your app content in Search results. Because Apple indexes web content and makes it available in Search and Safari, its crucial that you add markup to help Apple discover and index your content and display rich results.Adopting Smart App Banners is the best way to help users of your website discover your app. Including an app-argument in your Smart App Banner markup allows Apple to index your content.As an alternative to using Smart App Banners to describe deep links on your website, you can use one of the open standards Apple supports.Use standards-based markup for structured data (such as that defined atSchema.org) to annotate your web content so that users can see rich search results. For example, a recipe website might use the markup shown inListing 11to provide richer information about a recipe.Listing 11Using markup to provide more information

30 minutes Cook Time: 8 servings Ingredients: - 1/4 cup of flour egg - symbols and separate multiple protocols by a comma. Both options shown below will work just fine, but I prefer to keep them in the header file since it feels cleaner to me.Option 1: In your.hfile:#import "RPLocationManager.h"

@interface MyViewController : UIViewController

@end

Option 2: In the.mfile:#import "MyViewController.h"

@interface MyViewController () { // Class extension implementation}@end

Creating Your Own ProtocolTo create your own protocol for other classes to conform to, follow this syntax:RPLocationManager.h#import

// Declare your protocol and decide which methods are required/optional// for the delegate class to implement@protocol RPLocationManagerDelegate - (void)didAcquireLocation:(CLLocation *)location;- (void)didFailToAcquireLocationWithError:(NSError *)error;@optional- (void)didFindLocationName:(NSString *)locationName;@end@interface RPLocationManager : NSObject// Create a weak, anonymous object to store a reference to the delegate class@property (nonatomic, weak) id delegate;

// Implement any other methods here

@end

When we declare the@protocolnamedRPLocationManagerDelegate, all methods are defaulted to being@requiredso its not necessary to explicitly state this. However, if you want certain methods to be@optionalfor conforming classes to implement, you must state this.Additionally, it is necessary to weakly declare an anonymously typed property calleddelegatewhich also references theRPLocationManagerDelegateprotocol.Sending Delegate MessagesIn the example above,RPLocationManager.hdeclares some methods that the class which is acting as the delegate must implement. WithinRPLocationManager.mitself, you could implement these a few different ways, but well just show two cases: a) required methods; b) optional methods.

Required Methods- (void)updateLocation{ // Perform some work

// When ready, notify the delegate method [self.delegate didAcquireLocation:locationObject];}

Optional Methods- (void)reverseGeoCode{ // Perform some work

// When ready, notify the delegate method if ([self.delegate respondsToSelector:@selector(didFindLocationName:)]) { [self.delegate didFindLocationName:locationName]; }}

The only difference between@requiredand@optionalmethods is that you should always check if the referenceddelegateimplemented an optional method before calling it on that class.Implementing Delegate MethodsTo implement a delegate method, just conform to the protocol like was discussed earlier, and then write it as if it was a normal method:MyViewController.m- (void)didFindLocationName:(NSString *)locationName{ NSLog(@"We found a location with the name %@", locationName);}

SubclassingSubclassing is essentially the same asinheritance, but you would typically create the subclass to eitherOverride a method or property implementation in the superclass; orCreate specialized behavior for the subclass (e.g.Toyotais a subclass ofCar it still has tires, an engine, etc, but it has additional custom behavior that uniquely makes it aToyota)Many design patterns, such ascategoriesanddelegation, exist so that you dont have to subclass another class. For example, theUITableViewDelegateprotocol was created to allow you to provide the implementation of methods liketableView:didSelectRowAtIndexPath:in your own class instead of having to subclassUITableViewto override that method.Other times, classes likeNSManagedObjectare designed to be easily subclassed. The general rule of thumb is to subclass another class only if you can satisfy theLiskov substitution principle:If S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program.

ExampleLets assume that we want to model cars. All cars have similar behavior and characteristics, so lets put some of that in a superclass calledCar.Car.h#import

@interface Car : NSObject

@property (nonatomic, strong) NSString *make;@property (nonatomic, strong) NSString *model;@property (nonatomic, assign) NSInteger year;

- (void)startEngine;- (void)pressGasPedal;- (void)pressBrakePedal;

@end

Car.m#import "Car.h"

@implementation Car

- (void)startEngine{ NSLog(@"Starting the engine.");}

- (void)pressGasPedal{ NSLog(@"Accelerating...");}

- (void)pressBrakePedal{ NSLog(@"Decelerating...");}@end

Now when we want to spawn off new car makes and models with unique characteristics, we use theCarsuperclass as a starting point and then add custom behavior in the subclass.Toyota.h#import "Car.h"

@interface Toyota : Car

- (void)preventAccident;

@end

Toyota.m#import "Toyota.h"

@implementation Toyota

- (void)startEngine{ // Perform custom start sequence, different from the superclass

NSLog(@"Starting the engine.");}

- (void)preventAccident{ [self pressBrakePedal];

[self deployAirbags];}

- (void)deployAirbags{ NSLog(@"Deploying the airbags.");}

@end

Even thoughpressBrakePedalis declared in theCarclass, that method is still accessible in theToyotaclass due to inheritance.

Designated InitializersOften times, classes implement designated class initializers to allow for easy instantiation. If you override the main designated initializer for a class or provide a new designated initializer, its important to ensure that you also override all other designated initializers so they use your new implementation instead of the superclass version. If you forget to do so and someone calls one of the secondary designated initializers on your subclass, they will get behavior from the superclass instead.

// The new designated initializer for this class- (instancetype)initWithFullName:(NSString *)fullName{ if (self = [super init]) { _fullName = fullName; [self commonSetup]; } return self;}

// Provide a sensible default for other initializers- (instancetype)init{ return [self initWithFullName:@"Default User"];}

If youd rather someone not use a default initializer for some rare case, you should throw an exception and provide them with an alternative solution:- (instancetype)init { [NSException raise:NSInvalidArgumentException format:@"%s Using the %@ initializer directly is not supported. Use %@ instead.", __PRETTY_FUNCTION__, NSStringFromSelector(@selector(init)), NSStringFromSelector(@selector(initWithFrame:))]; return nil;}

Overriding MethodsIf youre subclassing another class to override a method within that class, you must be a little cautious. If you want to maintain the same behavior as the superclass, but just modify it slightly, you can callsuperwithin the override like this:- (void)myMethod{ [super myMethod];

// Provide your additional custom behavior here}

If you dont want any of the superclasss behavior for the overridden method, simply leave out that call tosuper, but be careful that there arent any memory or object lifecycle consequences for doing so.Additionally, if the superclass has primitive methods upon which other derived methods are implemented, you must ensure that you override all necessary primitive methods necessary for the derived methods to work properly.CaveatsCertain classes dont lend themselves well to being easily subclassed and therefore subclassing is discouraged in those cases. An example of this is when trying to subclass a class cluster such asNSStringorNSNumber. Class clusters have quite a few private classes within them so its difficult to ensure that you have overridden all of the primitive methods and designated initializers within the class cluster properly.

SwizzlingAs is often the case, clarity is better than cleverness. As a general rule, its typically better to work around a bug in a method implementation than it is to replace the method by using method swizzling. The reason being that other people using your code might not realize that you replaced the method implementation and then they are stuck wondering why a method isnt responding with the default behavior.For this reason, we dont discuss swizzling here but you are welcome toread up on it here.

Error HandlingErrors are typically handled three different ways: assertions, exceptions, and recoverable errors. In the case of assertions and exceptions, they should only be used in rare cases since crashing your app is obviously not a great user experience.AssertionsAssertions are used when you want to ensure that a value is what it is supposed to be. If its not the correct value, you force exit the app.NSAssert(someCondition, @"The condition was false, so we are exiting the app.");

Important: Do not call functions with side effects in the condition parameter of this macro. The condition parameter is not evaluated when assertions are disabled, so if you call functions with side effects, those functions may never get called when you build the project in a non-debug configuration.

ExceptionsExceptions are only used for programming or unexpected runtime errors. Examples: attempting to access the 6th element of an array with 5 elements (out-of-bounds access), attempting to mutate immutable objects, or sending an invalid message to an object. You usually take care of these sorts of errors with exceptions when an application is being created rather than at runtime.An example of this might be if you have a library which requires an API key to use.// Check for an empty API key- (void)checkForAPIKey{ if (!self.apiKey || !self.apiKey.length) { [NSException raise:@"Forecastr" format:@"Your Forecast.io API key must be populated before you can access the API.", nil]; }}

Try-CatchIf youre worried that a block of code is going to throw an exception, you can wrap it in a try-catch block but keep in mind that this has slight performance implications@try { // The code to try here}@catch (NSException *exception) { // Handle the caught exception}@finally { // Execute code here that would run after both the @try and @catch blocks}

Recoverable ErrorsMany times, methods will return anNSErrorobject in a failure block or as a pointer to a pointer (in the case ofNSFileManager). These are typically returned for recoverable errors and offer a much more pleasant user experience since they can clue the user into what just went wrong.[forecastr getForecastForLocation:location success:^(id JSON) { NSLog(@"JSON response was: %@", JSON);} failure:^(NSError *error, id response) { NSLog(@"Error while retrieving forecast: %@", error.localizedDescription);}];

Creating Your Own ErrorsIts also possible to create your ownNSErrorobjects to return in methods.// Error domain & enumsNSString *const kFCErrorDomain = @"com.forecastr.errors";typedef NS_ENUM(NSInteger, ForecastErrorType) { kFCCachedItemNotFound, kFCCacheNotEnabled};

@implementation Forecastr

- (void)checkForecastCacheForURLString:(NSString *)urlString success:(void (^)(id cachedForecast))success failure:(void (^)(NSError *error))failure{ // Check cache for a forecast id cachedItem = [forecastCache objectForKey:urlString]; if (cachedItem) { success(cachedItem); } else { // Return an error since it wasn't found failure([NSError errorWithDomain:kFCErrorDomain code:kFCCachedItemNotFound userInfo:nil]); }}

@end

Passing InformationWe have already discussed many ways of passing information between classes, such as through methods or delegates, but well discuss a few more here and also give one more example ofdelegation.Passing through DelegateA very common way to pass data from one view controller to another is to use a delegate method. An example of this would be if you had a modal view with a table that showed over top of your view controller and you needed to know which table cell the user pressed.AddPersonViewController.h (the modal view)#import #import "Person.h"

@protocol AddPersonTableViewControllerDelegate - (void)didSelectPerson:(Person *)person;@end

@interface AddPersonTableViewController : UITableViewController

@property (nonatomic, weak) id delegate;

@end

AddPersonViewController.m// Other implementation details left out

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ Person *person = [people objectAtIndex:indexPath.row]; [self.delegate didSelectPerson:person];}

GroupViewController.m (the normal view)// Other implementation details left out, such as showing the modal view// and setting the delegate to self

#pragma mark - AddPersonTableViewControllerDelegate

- (void)didSelectPerson:(Person *)person{ [self dismissViewControllerAnimated:YES completion:nil];

NSLog(@"Selected person: %@", person.fullName);}

We left out a few implementation details, such as conforming to theAddPersonTableViewControllerDelegate, but you are welcome to read thedelegationsection for those.Also, notice that we dismiss the modal view controller (AddPersonViewController) in the same class that originally showed it. This is the recommended approach by Apple.

NSNotificationCenterNotifications are broadcast messages that are used to decouple classes and establish anonymous communication between objects at runtime. Notifications may be posted by any number of objects and received by any number of objects thus enabling one-to-many and many-to-many relationships between objects.Note: Notifications are sent synchronously so if your observer method takes a long time to return, you are essentially prevently the notification from being sent to other observing objects.Registering ObserversYou can register to be notified when a certain event has happened, including system notifications, such as aUITextFieldwhich has begun editing.[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:self];

When theUITextFieldTextDidBeginEditingNotificationnotification is broadcast by the OS framework, thetextFieldDidBeginEditing:will be called byNSNotificationCenterand an object will be sent along with the notification that could contain data.

A possible implementation of thetextFieldDidBeginEditing:method could be:#pragma mark - Text Field Observers

- (void)textFieldDidBeginEditing:(NSNotification *)notification{ // Optional check to make sure the method was called from the notification if ([notification.name isEqualToString:UITextFieldTextDidBeginEditingNotification]) { // Do something }}

Removing ObserversIts important to remove yourself as an observer when the class is deallocated, otherwiseNSNotificationCenterwill attempt to call a method on a deallocated class and a crash will ensue.- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self];}

Posting NotificationsYou can also create and post your own notifications. Its best practice to keep notification names in aconstantsfile so that you dont accidentally misspell one of the notification names and sit there trying to figure out why the notification wasnt sent/received.

Naming notifications:Notifications are identified byNSStringobjects whose names are composed in this way:[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification

Declare a string constant, using the notification name as the strings value:// Remember to put the extern of this in the header fileNSString *const kRPAppDidResumeFromBackgroundNotification = @"RPAppDidResumeFromBackgroundNotification";

Post notification:[[NSNotificationCenter defaultCenter] postNotificationName:kRPAppDidResumeFromBackgroundNotification object:self];

View Controller PropertiesWhen you are preparing to display a new view controller, you can assign data to one of its properties prior to display:MyViewController *myVC = [[MyViewController alloc] init];myVC.someProperty = self.someProperty;[self presentViewController:myVC animated:YES completion:nil];

Storyboard SegueWhen you are transitioning from one view controller to another in a storyboard, there is an easy way to pass data between the two by implementing theprepareForSegue:sender:method:#pragma mark - Segue Handler

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ if ([segue.identifier isEqualToString:@"showLocationSearch"] { [segue.destinationViewController setDelegate:self]; } else if ([segue.identifier isEqualToString:@"showDetailView"]) { DetailViewController *detailView = segue.destinationViewController; detailView.location = self.location; }}

User DefaultsUser defaults are basically a way of storing simple preference values which can be saved and restored across app launches. It is not meant to be used as a data storage layer, like Core Data or sqlite.Storing ValuesNSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];[userDefaults setValue:@"Some value" forKey:@"RPSomeUserPreference"];[userDefaults synchronize];

Always remember to callsynchronizeon the defaults instance to ensure they are saved properly.Retrieving ValuesNSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];id someValue = [userDefaults valueForKey:@"RPSomeUserPreference"];

There are also other convenience methods onNSUserDefaultsinstances such asboolForKey:,stringForKey:, etc.

Common PatternsSingletonsSingletons are a special kind of class where only one instance of the class exists for the current process. They are a convenient way to share data between different parts of an app without creating global variables or having to pass the data around manually, but they should be used sparingly since they often create tighter coupling between classes.To turn a class into a singleton, you place the following method into the implementation (.m) file, where the method name is prefixed withsharedplus another word which best describes your class. For example, if the class is a network or location manager, you would name the methodsharedManagerinstead ofsharedInstance.+ (instancetype)sharedInstance{ static id sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; });

return sharedInstance;}

The use ofdispatch_onceensures that this method is only ever executed once, even if its called multiple times across many classes or different threads.If the above code were placed withinMyClass, then you would get a reference to that singleton class in another class with the following code:MyClass *myClass = [MyClass sharedInstance];[myClass doSomething];NSLog(@"Property value is %@", myClass.someProperty);

After reading so many articles Stackoverflow posts and demo applications to check variable property attributes, I decided to put all the attributes information together:atomic //defaultnonatomicstrong=retain //defaultweakretainassign //defaultunsafe_unretainedcopyreadonlyreadwrite //defaultBelow is the detailed article link where you can find above mentioned all attributes, that will definitely help you. Many thanks to all the people who give best answers here!!Variable property attributes or Modifiers in iOS1.strong (iOS4 = retain )it says "keep this in the heap until I don't point to it anymore"in other words " I'am the owner, you cannot dealloc this before aim fine with that same as retain"You use strong only if you need to retain the object.By default all instance variables and local variables are strong pointers.We generally use strong for UIViewControllers (UI item's parents)strong is used with ARC and it basically helps you , by not having to worry about the retain count of an object. ARC automatically releases it for you when you are done with it.Using the keyword strong means that you own the object.Example:@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;2.weak-it says "keep this as long as someone else points to it strongly"the same thing as assign, no retain or releaseA "weak" reference is a reference that you do not retain.We generally use weak for IBOutlets (UIViewController's Childs).This works because the child object only needs to exist as long as the parent object does.a weak reference is a reference that does not protect the referenced object from collection by a garbage collector.Weak is essentially assign, a unretained property. Except the when the object is deallocated the weak pointer is automatically set to nilExample :@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;Strong & Weak Explanation,Thanks to BJ Homer:Imagine our object is a dog, and that the dog wants to run away (be deallocated).Strong pointers are like a leash on the dog. As long as you have the leash attached to the dog, the dog will not run away. If five people attach their leash to one dog, (five strong pointers to one object), then the dog will not run away until all five leashes are detached.Weak pointers, on the other hand, are like little kids pointing at the dog and saying "Look! A dog!" As long as the dog is still on the leash, the little kids can still see the dog, and they'll still point to it. As soon as all the leashes are detached, though, the dog runs away no matter how many little kids are pointing to it.As soon as the last strong pointer (leash) no longer points to an object, the object will be deallocated, and all weak pointers will be zeroed out.When we use weak?The only time you would want to use weak, is if you wanted to avoid retain cycles (e.g. the parent retains the child and the child retains the parent so neither is ever released).3.retain = strongit is retained, old value is released and it is assigned retain specifies the new value should be sentretain on assignment and the old value sent -releaseretain is the same as strong.apple says if you write retain it will auto converted/work like strong only.methods like "alloc" include an implicit "retain"Example:@property (nonatomic, retain) NSString *name;

@synthesize name;4.assignassign is the default and simply performs a variable assignmentassign is a property attribute that tells the compiler how to synthesize the property's setter implementationI would use assign for C primitive properties and weak for weak references to Objective-C objects.Example:@property (nonatomic, assign) NSString *address;

@synthesize address;

The main components of Core Data.

Sqlite Vs CoredataSQLite:SQLite is, as advertised, lightweight.SQLite uses less memory and storage space.SQLite can be tedious and error-prone to code.SQLite is supported on Android and Microsoft Windows Phone.Core DataLonger learning curve: it takes some study to understand.Objects are easier to work with.Underlying storage details are handled atomically (support for iCloud).Undo and Redo features.

WHY YOU SHOULD USE COREDATA?PROPERTY LISTSIf you are not new to iOS/OSX programming, you have surely dealt with some file with a .plist extension. For example, the fileYourProjectName-Info.plistcontains information about your project configuration, such as the application name, the bundle identifier, the allowed orientation and so on. The property list are basically XML files handled by Xcode in a fancy way; they can store arrays, dictionaries, boolean, numbers, dates and data.This is a very limitative approach, in fact one problem with this method is that custom objects cannot be serialized into property lists.If you simply need to store an array of NSStrings, well this might be the best solution, you simply have to call thewriteToFile:atomically:method on your array and youre done! But Im sure you are here because you need a more consistent approach to data persistence..NSCODING + NSKEYEDARCHIVERThis was one of the first approaches to data persistence available in iOS since its birth. It is based on object modeling and the adoption of a protocol: NSCoding.By the implementation ofinitWithCoder:(NSCoder *)decoderandencodeWithCoder:(NSCoder *)encoderyou can specify the key to use in order to store a specific property of an object and then retrieve it when you need. With an NSKeyedArchiver you can store objects conforming to the NSCoding protocol and fetch them using an NSKeyedUnarchiver instance.Even if this is a very basic approach, you need to write a ton of code to save a simple object, it is not flexible and every time you have to change a property, you must update the code that stores it too. This is not only error-prone, but it lacks of an important feature: complex relationships. Just think about a one-to-many relationship between two objects, this could be a very difficult feature to implement. Another feature you will surely need is to perform a query on your model. Even if you need a simple join between two group of objects, with NSCoding would be a pain in your back.NSCoding+NSKeyed(Un)Archiver is a good option if your model is really simple and *-to-many relationship free.If you are interested in the NSCoding protocol and its application, I suggestthis article on NSHipster.SQLITE3Here we are, the good ol SQL based dbms!SQLiteis without of doubts the most powerful way to store your objects persistently, it provides all the features you need for this purpose: strong organization in tables, SQL language, powerful join features and nested queries and you can even creates indexes and triggers! As it often happens, if some framework gives you every possibility and the maximum flexibility, its likely to produce boiler-plate code. If youre not persuaded by this sentence, lets make a real-world example. Suppose we have a Message object containing an id,a sender, a receiver, a date and of course the message. This could be the code to create its Message Table: sqlite3 *database; if (sqlite3_open(DBPath, &database) != SQLITE_OK) { sqlite3_close(database); NSAssert(0, @"Failed to open database"); return; }

const char *createSQL = "CREATE TABLE IF NOT EXISTS MESSAGES" "(messageId INTEGER PRIMARY KEY,message TEXT,sender TEXT,receiver TEXT,date TEXT)"; sqlite3_exec(database, createSQL, NULL, NULL, &errorMsg);

if (errorMsg != NULL){ sqlite3_close(database); NSAssert(0, @"Failed to create TE_PROJECTS table: %s",errorMsg); return NO; } sqlite3_close(database);And this could be an example of a fetch operation: sqlite3 *database; if (sqlite3_open(DBPath, &database) != SQLITE_OK) { sqlite3_close(database); NSAssert(0, @"Failed to open database"); return; } NSString *query = [NSString stringWithFormat:@"SELECT message FROM MESSAGES WHERE messageId = 4"]; sqlite3_stmt *statement; NSString *savedMessage = nil; if (sqlite3_prepare_v2(database, [query UTF8String],-1, &statement, nil) == SQLITE_OK) { while (sqlite3_step(statement) == SQLITE_ROW) { char *message = (char *)sqlite3_column_text(statement, 0); savedMessage = @(message); } sqlite3_finalize(statement); } sqlite3_close(database);Finally this could be an insertion: sqlite3 *database; if (sqlite3_open(DBPath, &database) != SQLITE_OK) { sqlite3_close(database); NSAssert(0, @"Failed to open database"); return; } char *update = "INSERT OR REPLACE INTO MESSAGES (messageId,message,sender,receiver,date) VALUES (?,?,?,?,?);"; sqlite3_stmt *stmt; if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) == SQLITE_OK) { sqlite3_bind_int(stmt, 1, 34); sqlite3_bind_text(stmt, 2, "some spare text", -1, NULL); sqlite3_bind_text(stmt, 3, "John", -1, NULL); sqlite3_bind_text(stmt, 4, "Frank", -1, NULL) sqlite3_bind_text(stmt, 5, "2013-03-21", -1, NULL); } if (sqlite3_step(stmt) != SQLITE_DONE){ NSLog(@"Error inserting entry in table MESSAGES"); return; } sqlite3_finalize(stmt); sqlite3_close(database);This huge amount of code is the bare essential to have your object stored in a database. Just think about how many times you have to write the same code to create a table, to save a simple string or to fetch an object from your database! When you are repeating too much code too much times, there is always a better way to achieve the same result, and most of all someone surely have already done the job for you! This sounds good isnt it? Lets keep SQLite for our database intensive operations like creating a trigger or perform evil full outer join on tables and lets move on the subject of this article, Core Data.WHAT CORE DATA ISApple definition: The Core Data framework provides generalized and automated solutions to common tasks associated with object life-cycle and object graph management, including persistence.. This seems to be pretty simple and self-explanatory, Core Data is a framework that takes care of your data model, provides consistency mechanisms and deals with the file system/dbms to store data.WHAT CORE DATA IS NOTSince Apple tell us very well what Core Dat is not, I reported down here their definition: Core Data is not a relational database or a relational database management system (RDBMS).Core Data provides an infrastructure for change management and for saving objects to and retrieving them from storage. It can use SQLite as one of its persistent store types. It is not, though, in and of itself a database. (To emphasize this point: you could for example use just an in-memory store in your application. You could use Core Data for change tracking and management, but never actually save any data in a file.) Core Data is not a silver bullet.Core Data does not remove the need to write code. Although it is possible to create a sophisticated application solely using the Xcode data modeling tool and Interface Builder, for more real-world applications you will still have to write code.At this point your ideas may still be confused, I havent provided a true answer to the main question, I have only focused on the bad aspects of the other approaches. This article is not meant to be a Core Data tutorial, nor a deep focus on the technology, so to get things more concrete, the only thing I will do is providing a short example of storing and fetching data.HOW MANY CODE YOU NEED TO WRITE WITH CORE DATA?Lets take our previous example, the message Class:#import #import @interface Message : NSManagedObject@property (nonatomic, retain) NSNumber * messageId;@property (nonatomic, retain) NSString * sender;@property (nonatomic, retain) NSString * receiver;@property (nonatomic, retain) NSDate *date;@property (nonatomic, retain) NSString *message;@endThis is the interface of an auto-generated NSManagedObject subclass. Core Data creates automatically these objects for you, based on an Xcode Data Model Diagram. In this file you can graphically create your object s and the relationships between them, Core Data automatically crates the backend structure for you. Here is an example:

An xcode data model diagram example.Lets see how to store an instance of a managedObject: NSManagedObjectContext *moc = [[UIApplication delegate]managedObjectContext]; Message *message = (Message *)[NSEntityDescription insertNewObjectForEntityForName:@"Message" inManagedObjectContext:moc]; message.sender = @"SenderName"; message.receiver = @"receiverName"; message.message = @"Hello"; message.date = [NSDate date]; message.id = 123;

if (![moc save:&error]) { // Save failedNSLog(@"Core Data Save Error: %@, %@", error, [error userInfo]); }As you can see, at this point you havent written a single line of SQL, you didnt care about data formatting and file locations, Core Data did everything for you.Lets go ahead and see how to fetch a managed object from its context:NSManagedObjectContext *moc = [[UIApplication delegate]managedObjectContext];NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];[fetchRequest setEntity:[NSEntityDescription entityForName:@"Message" inManagedObjectContext:moc]];// Add a sort descriptor. Mandatory.NSSortDescriptor *desc = [NSSortDescriptor sortDescriptorWithKey:@"sender" ascending:YES];[fetchRequest setSortDescriptors:@[desc]];fetchRequest.predicate = [NSPredicate predicateWithValue:YES];NSError *error;NSArray *fetchResults = [moc executeFetchRequest:fetchRequest error:&error];if (fetchResults == nil) { // Handle the error. NSLog(@"executeFetchRequest failed with error: %@", [error localizedDescription]);}As you can see again, no SQL needed, no database instantiation, no C structures to handle. All you have to do is to learn how to use NSPredicate and NSSortDescriptor which are really,really easy to use. This seems to be anyway a lot of code to write every time, luckily there is a very good solution provided by Chris Miles which you can found ithere. What he does is simply create a set of generic functions to store, fetch and delete managed objects and perform a rollback in a managedObjectContext. If you decide to use Core Data, his approach is possibly the most clean and powerful to adopt.For example with his approach, storing an object would be this easy:[Message insertMessageWithSender:@"SenderName" receiver:@"ReceiverName" date:[NSDate date] id:@(123)];commitDefaultMOC();The top most feature of Core Data is that the related objects to an object instance are loaded for free. For example, lets say we have two Classes: Person and Car. A Person can own more cars, a car can be owned by only one person. Now insert a person and 3 cars in the context, assign to every car the person as the owner and perform save on the context. If you try to load the person you just stored and look at his cars property, you will see that all the 3 car instances are already loaded with their owner object! Just think about the effort you would have done to store and fetch a many to many relationship with SQLiteCONCLUSIONSIn this article we have covered a lot of aspects related to Core Data and its alternatives. Every approach has its pros and cons, and every one should be evaluated when we design the data persistence strategy. Core Data is indeed your first choice if the complexity of the model structure becomes a pain to manage.

Storyboards have a number of advantages over regular nibs:With a storyboard you have a better conceptual overview of all the screens in your app and the connections between them. Its easier to keep track of everything because the entire design is in a single file, rather than spread out over many separate nibs.The storyboard describes the transitions between the various screens. These transitions are called segues and you create them by simply ctrl-dragging from one view controller to the next. Thanks to segues you need less code to take care of your UI.Storyboards make working with table views a lot easier with the new prototype cells and static cells features. You can design your table views almost completely in the storyboard editor, something else that cuts down on the amount of code you have to write.

Prototype cells allow you to easily design a custom layout for your table view cells directly from within the storyboard editor.

This is one of the limitations of storyboards. With nibs you always had a reference to the App Delegate in your MainWindow.xib and you could make connections from your top-level view controllers to outlets on the App Delegate. That is currently not possible with storyboards. You cannot make references to the app delegate from your top-level view controllers. Thats unfortunate, but you can always get those references programmatically, which is what you do here.

whenever your data source asks the table view for a new cell withdequeueReusableCellWithIdentifier, the table view doesnt give you the actual prototype cell but acopyasegue(pronounce: seg-way) and represents a transition from one screen to another. A segue, on the other hand, changes what is on the screen. Segues are triggered by taps on buttons, table view cells, gestures, and so on.- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ if ([segue.identifier isEqualToString:@"AddPlayer"]) { UINavigationController *navigationController = segue.destinationViewController; PlayerDetailsViewController *playerDetailsViewController = [navigationController viewControllers][0]; playerDetailsViewController.delegate = self; }}

TheprepareForSegue:method is invoked whenever a segue is about to take place. The new view controller has been loaded from the storyboard at this point but its not visible yet, and you can use this opportunity to send data to it.

Handy checklist for setting up the connections between two scenes:Create a segue from a button or other control on the source scene to the destination scene. (If youre presenting the new screen modally, then often the destination will be a Navigation Controller.)Give the segue a unique Identifier. (It only has to be unique in the source scene; different scenes can use the same identifier.)Create a delegate protocol for the destination scene.Call the delegate methods from the Cancel and Done buttons, and at any other point your destination scene needs to communicate with the source scene.Make the source scene implement the delegate protocol. It should dismiss the destination view controller when Cancel or Done is pressed.ImplementprepareForSegue: in the source view controller and dodestination.delegate = self;.

Segues only go one way; they are only used to open a new screen. To go back you dismiss the screen (or pop it from the navigation stack), usually from a delegate. The segue is employed by the source controller only. The destination view controller doesnt even know that it was invoked by a segue. in iOS 6 they introduced a new concept: theunwind segue. With this new feature you can create segues that go back to the previous screen. That is what the green Exit icon is for in the storyboard.

NSObject UIResponder UIView UIScrollView ---> UITableViewDatasource Vs DelegateThe data source provides the table-view object with the information it needs to construct and modify a table view. The data source provides information that UITableViewneeds to construct tables and manages the data model when rows of a table are inserted, deleted, or reordered. The delegate manages table row configuration and selection, row reordering, highlighting, accessory views, and editing operations.

Datasource MethodsConfiguring a Table View tableView:cellForRowAtIndexPath: (Required) numberOfSectionsInTableView: tableView:numberOfRowsInSection: (Required) sectionIndexTitlesForTableView:

the trick to getting auto layout to work on aUITableViewCellis to ensure you have constraints to pin each subview on all sides that is, each subview should have leading, top, trailing and bottom constraints.

iOS 7 introduced a very important delegate method inUITableViewDelegate:- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;

This method allows a table view to calculate the actual height of each cell lazily, even deferring until the moment that tables needed.

Calculating dynamic-table-view-cell-height-auto-layout#import "RWBasicCell.h"static NSString * const RWBasicCellIdentifier = @"RWBasicCell";

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return [self basicCellAtIndexPath:indexPath];}- (RWBasicCell *)basicCellAtIndexPath:(NSIndexPath *)indexPath { RWBasicCell *cell = [self.tableView dequeueReusableCellWithIdentifier:RWBasicCellIdentifier forIndexPath:indexPath]; [self configureBasicCell:cell atIndexPath:indexPath]; return cell;}- (void)configureBasicCell:(RWBasicCell *)cell atIndexPath:(NSIndexPath *)indexPath { RSSItem *item = self.feedItems[indexPath.row]; [self setTitleForCell:cell item:item]; [self setSubtitleForCell:cell item:item];}- (void)setTitleForCell:(RWBasicCell *)cell item:(RSSItem *)item { NSString *title = item.title ?: NSLocalizedString(@"[No Title]", nil); [cell.titleLabel setText:title];}- (void)setSubtitleForCell:(RWBasicCell *)cell item:(RSSItem *)item { NSString *subtitle = item.mediaText ?: item.mediaDescription; // Some subtitles can be really long, so only display the // first 200 characters if (subtitle.length > 200) { subtitle = [NSString stringWithFormat:@"%@...", [subtitle substringToIndex:200]]; } [cell.subtitleLabel setText:subtitle];}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [self heightForBasicCellAtIndexPath:indexPath];}- (CGFloat)heightForBasicCellAtIndexPath:(NSIndexPath *)indexPath { static RWBasicCell *sizingCell = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sizingCell = [self.tableView dequeueReusableCellWithIdentifier:RWBasicCellIdentifier]; }); [self configureBasicCell:sizingCell atIndexPath:indexPath]; return [self calculateHeightForConfiguredSizingCell:sizingCell];}- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell { [sizingCell setNeedsLayout]; [sizingCell layoutIfNeeded]; CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; return size.height + 1.0f; // Add 1.0f for the cell separator height}

tableView.estimatedRowHeight = 68.0tableView.rowHeight = UITableViewAutomaticDimensionThe first line of code sets the estimated row height of the cell, which is the height of the existing prototype cell. The second line changes the rowHeight property to UITableViewAutomaticDimension, which is the default row height in iOS 8. In other words, you tell table view to figure out the cell size based on other information.

Dynamic Type was introduced in iOS 7. It allows users to customise the text size to fit their own needs. However, only apps that adopt Dynamic Type respond to the text change. I believe only a fraction of third-party apps have adopted the feature.Autolayout If youve used an asset library in the past then youll notice something strange here whats this3xall about?This new display scale is known as Retina HD and is found on the iPhone 6 Plus. This means that in each direction, there are actually 3 pixels making up one point i.e. there are 9 times more pixels in a3ximage than a1ximage!

Use Auto Layout to define relationshipconstraintsfor your apps user interface so that when one item changes its size or position, that item and its neighboring items adjust their sizes and positions appropriately. For example, you can center an image horizontally in a storyboard scene. As the user rotates the iOS device, the image remains horizontally centered in both landscape and portrait orientations of the device.

The rule underneath the hood is just a linear equation:FirstItem.Attribute1 = (SecondItem.Attribute2 * Multiplier) + Constant

With Auto Layout constraints governing the layout, the items in your user interface automatically resize and reposition themselves whenever: The user changes the screen orientation of an iOS device The user resizes a window in a Mac app Content dimensions change (for example, when the length of a text string changes in a label or button)

Theframe rectangleis the raw frame of the view element.Thealignment rectangleis the total visual space occupied by the view element including any runtime adornments. It can be different than the frame rectangle.

Intrinsic Content SizeWith Auto Layout, a views content plays as important a role in its layout as its constraints. This is expressed through each viewsintrinsicContentSize, which describes the minimum space needed to express the full view content without squeezing or clipping that data. It derives from the natural properties of the content that each view presents.

Cocoa Autolayout: content hugging vs content compression resistance priority Hugging => content does not want to grow Compression Resistance => content does not want to shrinkan example:Say you've got button like this:[ Click Me ]and you've pinned the edges to a larger superview with priority 500.Then, if Hugging priority > 500 it'll look like this:[Click Me]If Hugging priority < 500 it'll look like this:[ Click Me ]If superview now shrinks then, if the Compression Resistance priority > 500, it'll look like this[Click Me]Else if Compression Resistance priority < 500, it could look like this:[Cli..]If it doesn't work like this then you've probably got some other constraints going on that are messing up your good work!E.g. you could have it pinned to the superview with priority 1000. Or you could have a width priority. If so, this can be helpful:Editor > Size to Fit Content

Constraint attributes.Every constraint for an item includes an attribute that relates to the size or position of the itemsalignment rectangle. (Because the alignment rectangle is based on the presentation of the items content, Auto Layout uses the alignment rectangle instead of the items frame rectangle.

The attributes fall into three categories: Horizontal positioning:Leading, Trailing, Left, Right, and Center Vertical positioning:Top, Bottom, Center, and Baseline Size:Width, Height, and Aspect Ratio

Left refers to the left edge of an items alignment rectangle, Bottom refers to the bottom edge of an items alignment rectangle, Width refers to the width of an items alignment rectangle, and so forth. With constraints, you align these rectangles, define the space between them, and size them.

Leading refers to the edge of the alignment rectangle where words and sentences begin; Trailing refers to the edge where words and sentences end. For left-to-right languages such as English, Leading is the same as Left, whereas in a right-to-left environment such as Hebrew or Arabic, Leading is the same as Right. Similarly, Trailing is the same as Right for English, but Trailing is the same as Left for Hebrew and Arabic. You should use Leading and Trailing to make sure your interface is laid out appropriately in all languages, unless the horizontal position should remain fixed at left or right regardless of the language.

The Baseline attribute is available only for items that have baselines. Baseline refers to an invisible line, offset from the bottom of the alignment rectangle, along which glyphs of characters are laid out.

For a size attribute, you can specify a fixed number of points (such as a width of 80), a proportional relationship (for example, defining the width of one item to be twice the width of another), or an aspect ratio (for example, defining the width of an item to be twice its height).

Priorities.You can specify the degree of precedence Auto Layout uses to satisfy the constraint compared with other constraints in the superview. New constraints are created with a default priority of 1000, which makes them required. Generally, you wont need to change the default priority. However, if you find constraints interacting in some unintended way, giving a lower priority to a less critical constraint may resolve the problem. Perhaps, for example, horizontally spaced controls become clipped when their container view becomes too narrow. By reducing the priority for the width of the controls or the priority for their horizontal spacing in this example, the container view can become narrow without clipping the controls.

Size classes.To most easily deploy an iOS app to different devices in different orientations, use size classes in conjunction with layout constraints. Begin by laying out your design abstractly, as if for a generic device. To design for more specific form factors, choose appropriate size classes, then add, remove, or edit layout constraints as needed.

A size class is a convenient new technology that forcesdevelopersto stop thinking in terms of specific devices (e.g iPhone 4, iPhone 5, iPad) and instead use a more generalised approach. Designing for size classes saves development time and makes supporting futuredevices with potentially new sizes easier.

VerticallyHorizontally

iPhone PortraitRegularCompact

iPhone LandscapeCompactCompact

iPhone 6 Plus LandscapeCompactRegular

iPad PortraitRegularRegular

iPad LandscapeRegularRegular

Apple introducedAdaptive UI, a new method of building apps that are adaptive to the size and characteristics of the container they are run in instead of targeting a particular device. A core concept of Adaptive UI is the use of Size Classes. Size classes define the canvas size used in layouts. When creating an apps UI, you specify layout rules based on Size Classes and these will determine how your UI looks and changes when the available size of your view controller changes.A size class can be eithercompactorregularand it identifies a relative amount of display space for the height (vertical) and for the width (horizontal).

Sizes of iPhone UI Elements

ElementiPhone 4S (and earlier)iPhone 5iPhone 6iPhone 6 Plus

Window (including status bar area)320 x 480 pts320 x 568 pts375 x 667 pts414 x 736 pts

iOS8 PortraitKeyboard(English)with QuickType320 x 253 pts320 x 253 pts375 x 258 pts414 x 271 pts

iOS8 PortraitKeyboard(English)without QuickType320 x 224 pts320 x 224 pts375 x 225 pts414 x 236 pts

iOS8 LandscapeKeyboard(English)with QuickType480 x 193 pts568 x 193 pts667 x 194 pts736 x 194 pts

iOS8 LandscapeKeyboard(English)without QuickType480 x 170 pts568 x 170 pts667 x 171 pts736 x 171 pts

Launch Image Sizes640 x 960 pixels640 x 1136 pixels750 x 1334 (@2x) portrait1334 x 750 (@2x) landscape1242 x 2208 (@3x) portrait2208 x 1242 (@3x) landscape

Other dimensions common to all screen sizes:Status Bar(How to hide the status bar)20 pts

Navigation Bar44 pts

Nav Bar/Toolbar Iconwhite icon - up to 20 x 20 pts (transparent PNG)

Tab Bar49 pts

Tab Bar Iconup to 30 x 30 pts (transparent PNGs)

Text Field31 pts

Points vs. PixelsApple introduced retina displays starting with the iPhone 4. You don't have to modify your code to support high-res displays; the iOS coordinate system uses points rather than pixels, so the dimensions and position in points of all UI elements remains the same across all devices.iOS supports high resolution displays via thescaleproperty on UIScreen, UIView, UIImage, and CALayer classes. If you load an image from a file whose name includes the @2x modifier, its scale property is set to 2.0. Similarly an image with a @3x modifier has a scale of 3.0. Otherwise the scale defaults to 1.0.Retina GraphicsTo support high-resolution graphics on devices with retina displays, create two versions of the image: a standard size image, and a double-sized image with "@2x" added to the name:Standard Size:High Resolution:

button.png60 x [email protected] x 40

To refer to an image in your code (or in Interface Builder), use the filename of the standard sized image. iOS will automatically detect and use the @2x version if the device supports it:imageView.image = [UIImage imageNamed:@"button.png"];

Detecting iPhone Device SizesTop of Form

Bottom of FormScreen DimensionsTo get the screen dimensions (in points) of the current device:CGRect screenBounds = [[UIScreen mainScreen] bounds];On the iPhone 5, the screen height is 568. On earlier iPhone models, it's 480. On the iPad, it's 1024.You can use the following macro to detect if it's a 4" (568-pixel) screen (add below the#importdirectives, or add to your app's mainAppname-Prefix.pch file to make it globally accessible):#define IS_WIDESCREEN ( [ [ UIScreen mainScreen ] bounds ].size.height == 568 )Then in theviewDidLoadmethod, use the macro to do any special setup needed for the iPhone 5 screen:if (IS_WIDESCREEN) { topParchment.hidden = NO; endSongButn.hidden = NO;}(Though, the recommended way of dealing with varying screen sizes is to useAuto Layout. See also Ray Wenderlich'sAuto Layout Tutorial.)

Device ModelIf you need to detect whether the current device is an iPhone, iPod, or iPad, use the UIDevice class'smodelmethod:NSLog(@"Current device: %@", [[UIDevice currentDevice] model] );

Use caution when looking for "iPhone" in the device string - you don't want to exclude the iPod touch! Here are several macros that might be handy (save these to your Appname-Prefix.pch file to make them globally available):#define IS_WIDESCREEN_IOS7 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )#define IS_WIDESCREEN_IOS8 ( fabs( ( double )[ [ UIScreen mainScreen ] nativeBounds ].size.height - ( double )1136 ) < DBL_EPSILON )#define IS_WIDESCREEN ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_WIDESCREEN_IOS8 : IS_WIDESCREEN_IOS7 )

#define IS_WIDESCREEN ( [ [ UIScreen mainScreen ] bounds ].size.height == 568 )#define IS_IPHONE ( [[[UIDevice currentDevice] model] rangeOfString:@"iPhone"].location != NSNotFound )#define IS_IPAD ( [[[UIDevice currentDevice] model] rangeOfString:@"iPad"].location != NSNotFound )

#define IS_IPHONE5 ( !IS_IPAD && IS_WIDESCREEN )Retina Display?To determine if the device has a retina display:CGFloat screenScale = [[UIScreen mainScreen] scale];Non-retina devices have a scale of 1.0. Retina devices have a scale of 2.0.

Top of FormView Frames and BoundsBottom of FormA computer screen has its own 2d coordinate system that allows the software to display objects at a certain location on screen.The iPhone's screen is 320 points wide by 480 points high.The top left corner is the origin (x=0, y=0). Positive values of x go right across the screen, while positive values of y go down the screen.View otherSizes of iPhone UI Elements

Every UIView object, including windows, full-screen views, labels, buttons and other controls has its ownframeproperty which describes the location (x/y coordinates) of the view within its superview, as well as the width and height of the view.

The frame is a Cstructuretype with structure members for the origin and size:UIView'sframeproperty:TheCGPointdata type:TheCGSizedata type:

struct CGRect { CGPoint origin; CGSize size;};struct CGPoint { CGFloat x; CGFloat y;};struct CGSize { CGFloat width; CGFloat height;};

You can position a view by assigning its frame to a CGRect:[button setFrame:CGRectMake(x, y, width, height)];Viewing / Adjusting Sizes in Interface BuilderWhen you drag elements around in Interface Builder, you're actually changing theirframeproperty; Interface Builder just makes it easy to do. Sizes for specific UI elements can also be adjusted in the size panel (3) of the Inspector window:

You can either drag the item around on screen, or type new numbers into the x/y/width/height boxes in the size panel to resize or reposition an object.

Frame and BoundsTheframeis the outer container for the view - the position of the item within its enclosing superview.Theboundsrectangle determines the origin and scale in the view's coordinate systemwithinits frame rectangle. Setting this property changes the value of the frame property accordingly.When you set the frame property, the size of the bounds property is set to match the size of the frame property. The center property is also adjusted to match the center point of the new frame.Page | 121