Migration vers iOS7

A compter du 1er février, toutes les applications soumises sur l'AppStore devront être construites avec Xcode5 et "optimisées" iOS7 (cf. news Apple du 17 décembre). Avec une part de marché proche de 80% pour iOS7 (cf mesures d'Apple), la nouvelle version du système mobile d'Apple devient un incontournable pour les développeurs d'applications mobiles. La part de marché est telle que l'on peut dores et déjà abandonner le support des versions antérieures à iOS6, voire même se limiter au support d'iOS7. Ne se limitant pas à une simple migration technique, iOS7 introduit un tout nouveau design (dénommé 'Flat Design') qu'il convient également de prendre en compte dans les applications iOS. Nous vous conseillons de lire le guide Apple qui est un point d'entrée incontournable pour migrer vers iOS7: iOS 7 UI Transition Guide. Après s'être confronté à l'exercice plus ou moins douloureux de la migration technique d'applications vers iOS7, voici notre retour d'expérience, montrant les différents problèmes rencontrés et les solutions que nous avons mises en place avec succès. A vos Xcode 5!

La nouvelle apparence par défaut de UITableViewCell

Le Flat Design d'iOS7 introduit de nouvelles apparences par défaut. C'est notamment le cas de UITableViewCell. Prenons le cas d'une UITableView contenant des UITableViewCell. La seule personnalisation réalisée ici est le passage en bleu de la couleur de fond de la UITableView. On a donc sous iOS6 l'apparence de gauche, alors que si on exécute l'application sous iOS7, l'apparence est celle de droite :

iOS6 - UITableViewCelliOS7 - UITableViewCell Before

On remarque que le fond bleu de la UITableView n'est pas visible, la faute à la couleur de fond des UITableViewCell qui est désormais blanche par défaut. De plus les séparateurs de cellules ne sont pas de la largeur de la cellule. En effet, iOS7 introduit un nouveau paramètre qui est le separatorInset des cellules. Ce paramètre permet de "décaler" le séparateur. Pour avoir une apparence identique sur iOS6 et iOS7, il est donc nécessaire d'ajouter les 2 lignes suivantes lors de la création de la cellule.

// Set background color to clear as in iOS7 default background color is white
[cell setBackgroundColor:[UIColor clearColor]];
// Be careful: you SHALL test if the cell responds to setSeparatorInset to keep iOS6 compatibility
if ([cell respondsToSelector:@selector(setSeparatorInset:)])
{
    [cell setSeparatorInset:UIEdgeInsetsZero];
}

Voici alors le résultat sous iOS7.

iOS7 - UITableViewCell After

Comment gérer la nouvelle status bar transparente

Si on observe bien l'exemple précédent, on remarque que sous iOS7 la première cellule est en partie masquée par la status bar. Cela est dû au fait que le Flat Design d'iOS7 a introduit une status bar transparente qui se positionne en avant plan de toutes les vues. Le premier réflexe est de décaler toutes les vues de 20 pixels vers le bas, soit dans les XIBs (long et fastidieux) soit dans le code. Heureusement, Xcode5 permet de paramétrer ce delta iOS6 vs iOS7 directement dans le XIB. Pour cela, il faut que l'autolayout soit désactivé, puis régler le positionnement de la vue du contrôleur en iOS6 et en iOS7 en sélectionnant la visualisation appropriée dans le champ "View as..."

Capture d’écran 2014-01-30 à 11.14.43Capture d’écran 2014-01-30 à 11.23.10

Cela a pour effet de modifier les paramètres Delta iOS6/iOS7 du XIB:

Capture d’écran 2014-01-30 à 11.39.24

Voici alors le résultat sous iOS7:

Capture d’écran du Simulateur iOS 30 janv. 2014 12.12.47

Comment créer correctement une UITableViewCell

Tous les contrôles de votre UITableViewCell ne sont plus actifs? Etes-vous sûrs d'avoir correctement créé votre cellule lors de la création du XIB correspondant? Explications: Lors de la création d'un fichier XIB avec Xcode, le premier élément créé est une UIView. Même si vous spécifiez dans le '.h' de votre cellule que votre objet hérite d'une UITableViewCell, la hiérarchie de vue contient une seule UIView.

Capture d’écran 2014-01-30 à 14.24.24

Capture d’écran 2014-01-30 à 14.24.28

Or, sous iOS7, la contentView de la UITableViewCell va alors être ajoutée par-dessus toutes vos sous-vues, rendant inaccessibles vos contrôles. Pour corriger ce problème, il est nécessaire de toujours remplacer la vue parente de votre UITableViewCell custom par une UITableViewCell.

Capture d’écran 2014-01-30 à 14.02.44

L'obsolescence de sizeWithFont.

Si vous aviez l'habitude de définir dynamiquement la hauteur de vos label via 'sizeWithFont' vous remarquerez que cette méthode retourne désormais des résultats erronés. Il convient désormais d'utiliser 'boundingRectWithSize'. Voici un exemple d'implémentation pour calculer la hauteur d'un texte quelque soit la font utilisée, et permettant la compatibilité iOS6/iOS7.

+ (CGFloat)heightForString:(NSString *)text withWidth:(CGFloat)width font:(UIFont *)font
{
    CGSize constraint = CGSizeMake(width, CGFLOAT_MAX);
    CGFloat height = 0;

    if (IS_IOS7_OR_UPPER)
    {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.minimumLineHeight = kMinLineHeight;
        CGRect textRect = [text boundingRectWithSize:constraint
                                             options:NSStringDrawingUsesLineFragmentOrigin |                    
                                                     NSStringDrawingUsesFontLeading
                                          attributes:@{NSFontAttributeName: font,
                                                       NSParagraphStyleAttributeName: paragraphStyle}
                                             context:nil];
        height = ceilf(textRect.size.height);
    }
    else
    {
       height = [text sizeWithFont:font 
                 constrainedToSize:constraint                                   
                     lineBreakMode:UILineBreakModeWordWrap].height;
    }

    return height;
}

Les IBOutletCollections

Si vous utilisiez une IBoutletCollection et que vous basiez certains comportements de votre application sur l'index des objets contenus dans l'IBoutletCollection, vous risquez quelques surprises désagréables. En effet, la conversion du XIB d'Xcode4.6 à Xcode5 entraîne parfois une modification de l'ordonnancement des objets dans l'IBoutletCollection. Pour résoudre le problème, il est nécessaire de supprimer le lien vers l'IBoutletCollection dans le XIB, puis de la recréer dans l'ordre requis.

La nouvelle hiérarchie du UIPageControl

Vous aviez embelli votre UIPageControl avec de belles images pour remplacer les "points" par défaut, mais sous iOS7, dès l'exécution vous avez un crash, pas de panique! Cela est dû aux sous vues de UIPageControl qui ne sont plus des UIImageView mais désormais des UIView, et donc ne peuvent être modifiées via la méthode 'setImage:'. Il est donc nécessaire de créer une UIImageView et de la positionner dans la sous vue correspondante de votre UIPageControl. Pour une description et une implémentation concrète, rendez-vous sur cet article de stackoverflow.

BONUS TRACK: comment avoir un texte blanc dans la status bar

Si vous souhaitez avoir une status bar avec un texte blanc, il faut dans un premier temps ajouter la clef "View controller-based status bar appearance" et passer sa valeur à 'YES'.

PlistIl faut ensuite, dans chaque ViewController (l'idéal est de créer un ViewController parent) implémenter 'preferredStatusBarStyle' comme suit:

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

Capture d’écran du Simulateur iOS 30 janv. 2014 12.10.57