Accéder au contenu principal

Articles

Affichage des articles du 2019

Sélecteur de fichier (Open) avec MacCatalyst

Dans mon précédent article sur UIMenuBuilder avec MacCatalyst, je créais une entrée de menu open dans le menu Fichier par défaut. Cette entrée lançait la fonction importfile: dans le Responder en cours. Mais je n'expliquais pas comment ouvrir le sélecteur de fichiers... Voici le code à ajouter dans le ViewController principal : #pragma mark - Import File #if TARGET_OS_MACCATALYST - ( void ) documentPickerWasCancelled :( UIDocumentPickerViewController *)controller {     NSLog ( @"documentPickerWasCancelled:" ); } - ( void ) documentPicker :( UIDocumentPickerViewController *)controller didPickDocumentsAtURLs :( NSArray < NSURL *> *)urls {     NSLog ( @"documentPicker:didPickDocumentsAtURLs:" );     UIApplication *app = [ UIApplication sharedApplication ];     for ( NSURL *url in urls) {         if ([app. delegate application :app openURL :url options : @{ } ]== NO ) {             [ Usefull AlertWithTitle :url. descr

Lire des fichiers dans iCloud

Lorsque vous faites une application IOS, vous pouvez attacher des types de fichiers à votre application ce qui permet par exemple de faire des fichiers de sauvegarde. Dans le delegate de votre UIApplication, vous avez une fonction qui sera appelée lorsque vous copier un fichier dans votre application. -( BOOL ) application :( UIApplication *)application openURL :( NSURL *)url options :( nonnull NSDictionary < UIApplicationOpenURLOptionsKey , id > *)options; Dans cette fonction vous recevez l'URL du fichier. Si vous recevez un document attaché par email et que vous le copier dans votre app, cela copiera réellement le fichier dans un répertoire Mail qui se trouve dans le répertoire de votre application. Pas de problème vous pouvez accéder aux fichiers directement. Mais lorsque vous tapez un fichier dans le cloud, le fichier ne se trouve pas dans votre répertoire (sandbox) et vous ne pouvez pas l'ouvrir car vous n'en avez pas les droits. Vous devez alors appe

UIMenuBuilder avec MacCatalyst

Lorsque l'on porte une application IOS sur MacCatalyst, se pose la question du menu. Ici je voulais ajouter un menu "Open" à mon application, mais comment faire ? J'ai mis mon code entre "#if TARGET_OS_MACCATALYST" car ce code fonctionne aussi avec IOS el la notion de UIMenuBuilder n'apparait que dans IOS13, or je développe mes application pour IOS9 car beaucoup d'utilisateurs ont des vieux appareils... #if TARGET_OS_MACCATALYST -( void ) buildMenuWithBuilder :( id )builder {     NSLog( @"buildMenuWithBuilder !!" );     [ super buildMenuWithBuilder:builder];     if (builder.system == UIMenuSystem.mainSystem) {         [builder removeMenuForIdentifier:UIMenuFormat];          // Le menu "Format" ne m'interresse pas         // On crée la commande...          //L'action doit être une fonction déclarée dans le FirstResponder         UIKeyCommand *command_O = [UIKeyCommand                   c

[General] UIDocumentInteractionController not available

Lorsque l'on porte une application sur Mac Catalyst, il y a un problème avec les UIDocumentInteractionController... Les logs disent : [General] UIDocumentInteractionController not available Dans ce cas, là plusieurs cas de figure... Cas 1 :  On essaye juste de visualiser un fichier standard, par exemple un PDF... Dans ce cas on peut remplacer le document interactif par un simple open. Dans l'application IOS il faut laisser le document interactif car sinon on sort de l'application. Mais sur un Mac ce n'est pas grave. -( IBAction ) info :( UIButton *)sender {     NSURL * url = [[ NSBundle mainBundle ] URLForResource : @"TaPytha" withExtension : @"pdf" ]; #if TARGET_OS_MACCATALYST     [[ UIApplication sharedApplication ] openURL :url options : @{} completionHandler : nil ]; #else     documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:url];     assert(documentInteractionController)

Sélecteur non reconnu.

Il arrive qu'un objet Objective-C ne pointe pas sur la bonne classe. Par exemple on met un cast sur un objet, celui-ci est un NCDictionary et on croit que c'est un NSString. Dans ce cas l'application plantera par exemple avec un appel à "length" qui existe en NSString mais pas en NSDictionary. Malheureusement, la plupart du temps le débuggeur vous emmènera à "main()" à la place de la ligne qui a causé le plantage. Pour cela vous pouvez ajouter un "symbolic breakpoint" avec dans "symbol" : -[NSObject doesNotRecognizeSelector:]

_UISheetInteractionBackgroundDismissRecognizer

Avec IOS13 les FormSheet et les PageSheet peuvent être quittés par un geste de glissement vers le haut. Mais si votre UIViewController contient un élément qui utilise les déplacements de doigts (UITouch) alors cela ne fonctionne plus à cause de la gestion de ce geste. Pour désactiver le geste, utilisez le code suivant : -( void ) viewDidAppear :( BOOL )animated {     [ super viewDidAppear :animated];     for ( UIGestureRecognizer *gr in self . presentationController . presentedView . gestureRecognizers ) {         if ( @available (iOS 11.0 , *)) {             if ([gr. name isEqualToString : @"_UISheetInteractionBackgroundDismissRecognizer" ]) {                 // disable la possibilité de quitter la feuille FormSheet ou PageSheet avec un glissement vers le haut                 gr. enabled = false ;             }         }     } }

TARGET_OS_MAC

Lorsque l'on désire compiler différemment selon que l'on soit sur iPhone ou sur Mac, naturellement on fait : #if TARGET_OS_MAC   // code pour le mac #else   // code pour iPhone iPad #endif Mais l'on a tort ! Car TARGET_OS_MAC renvoie 1 même si l'on est sous iPhone ! Il faut inverser le test pour que cela fonctionne : #if TARGET_OS_IPHONE   // code pour iPhone iPad #else   // code pour le mac #endif Ou utiliser TAGET_OS_OSX qui lui renvoie zéro avec un iPhone et un iPad. #if TARGET_OS_OSX   // code pour le mac #else   // code pour iPhone iPad #endif C'est nul, je sais... Mais il faut le savoir, un iPhone est un Mac... Au passage, vous pouvez aussi pour être plus précis utilisez TARGET_OS_MACCATALYST.

Parcourir des dates avec NSDate

Pour utiliser NSDate nous avons besoin de dire de quoi nous parlons... En effet une date n'a de sens que par rapport à un calendrier (Arabe, Hébreux, Japonais, etc...). Notre calendrier (à nous français) est le calendrier grégorien. Nous avons donc besoin d'une variable NSCalendar initialisée en grégorien. NSCalendar * calendar = [[ NSCalendar alloc ] initWithCalendarIdentifier :  NSCalendarIdentifierGregorian ]; Ensuite si nous avons besoin de récupérer un élément de la date, nous avons besoin d'une variable NSDateComponent NSDateComponents * components = [calendar components : NSCalendarUnitYear | NSCalendarUnitMonth |  NSCalendarUnitDay fromDate :[ NSDate new ]]; Le  [ NSDate new ] fournit la date du jour. Vous devez définir quelles parties de la date vous intéresse, quels composants. Ici, par exemple nous coulons récupérer : - L'année : NSCalendarUnitYear - Le mois : NSCalendarUnitMonth - Le jour dans le mois : NSCalendarUnitDay Après, nous

UICollectionViewCell frame

Pour avoir le rectangle correspondant à une cellule d'une UICollectionView, il faut utiliser  layoutAttributesForItemAtIndexPath, par exemple pour afficher un menu  :     menu = [UIMenuController sharedMenuController];     menu.menuItems = items;     UICollectionViewLayoutAttributes * theAttributes = [collectionView layoutAttributesForItemAtIndexPath:indexPath];     CGRect frame = [collectionView convertRect:theAttributes.frame toView:collectionView];     [menu setTargetRect:frame inView:collection]; // self.view];     [menu setMenuVisible: YES animated: YES ]; Attention, j'utilisais avant IOS13 la fonction cellForIndexPath:, mais celle-ci renvoie nil avec IOS13.

Patron pour la création d'icône Apple

Trucs pour xCode

Script pour le numéro de version du bundle

Trucs pour xCode Chaque mise à jour officiel a un numéro de série simple, mais chaque mise à jour de bêta doit avoir un numéro de version du bundle plus important que la précédente mise à jour. Suivez les instructions qui suivent pour ne plus vous en occuper (le numéro de version de Bundle sera incrémenté à chaque compilation). Allez dans "Build Phase", tapez le "+", et insérez un "New run script phase" avec le code ci-dessous. Placez cette phase le plus haut possible (juste en dessous du "Target Dependencies"). #!/bin/bash buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE") buildNumber=$(($buildNumber + 1)) /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

Utilisation d'images vectorielles

Trucs pour xCode Les formats images supportés par IOS sont le PNG, le JPG, et ... le PDF ! Si vous souhaitez utiliser du vectoriel, il faut donc imprimer votre image dans un PDF et utiliser ce PDF comme image. Personnellement j'utilise Inkscape pour faire les icônes de mes applications. Lorsque vous intégrez votre PDF dans les assets, n'oubliez pas de mettre "Preserve Vector Data" sinon votre PDF aura beau être vectoriel, l'application en fera une image. Ensuite vous pouvez aussi mettre "Single scales" puisque tout l'intérêt du vectoriel est justement de na pas gérer les résolutions.

Interface Builder - Failed to load designables from path (null)

Trucs pour xCode Il arrive que Interface Builder plante et soit incapable d'afficher correctement l'interface avec le message d'erreur :  Interface Builder - Failed to load designables from path (null). Dans ce cas, allez dans le "build settings" du projet, trouvez le réglage " Runpath Search Paths " et ajoutez  $(CONFIGURATION_BUILD_DIR)