Git: file is missing

Quando si usare git su Xocde può capitare che qualcosa vada storto e dei file, magari semplicemente spostati da una cartella ad un altra, risultino mancanti.

È questo il caso di quando appare nella schermata del Commit un punto interrogativo a fianco ad un file e nell’editor di fianco il messaggio:

1
file is missing
file is missing

Ovviamente questo può accadere anche ad una cartella.

Per ovviare a questo fastidioso problema, che provoca anche dei relativi Warning in fase di compilazione, è sufficiente aprire il Terminale, posizionarsi nella cartella del progetto, e forzare un commit con questo comando:

1
git commit -a -m "Commit Message"
git commit -a -m "Commit Message"

A volte, se avete più Xocde installati, potrebbe essere necessario specificare dove si trova la versione che state usando:

1
sudo xcode-select --switch /Applications/Xcode\ 8/Xcode.app
sudo xcode-select --switch /Applications/Xcode\ 8/Xcode.app

Dichiarare un block type per un completion handerl

In relazione all’articolo Creare un completion handler, si può precisare quanto illustrato qui:

La dichiarazione del block type è un modo per rendere più facilmente modificabile la signature del metodo, poiché nel primo caso basta cambiare la definizione del blocco, senza toccare il metodo.

1
2
3
4
typedef BOOL (^SomeBlockType)(id object, NSUInteger idx, BOOL *stop);
 
- (void)collectionToCheck:(SomeBlockType)checkerBlock;
- (void)singleItemToCheck:(SomeBlockType)checkerBlock;
typedef BOOL (^SomeBlockType)(id object, NSUInteger idx, BOOL *stop);

- (void)collectionToCheck:(SomeBlockType)checkerBlock;
- (void)singleItemToCheck:(SomeBlockType)checkerBlock;

versus:

1
2
- (void)collectionToCheck:(BOOL(^)(id object, NSUInteger idx, BOOL *stop)) checkerBlock;
- (void)singleItemToCheck:(BOOL(^)(id object, NSUInteger idx, BOOL *stop)) checkerBlock;
- (void)collectionToCheck:(BOOL(^)(id object, NSUInteger idx, BOOL *stop)) checkerBlock;
- (void)singleItemToCheck:(BOOL(^)(id object, NSUInteger idx, BOOL *stop)) checkerBlock;

Local notification: da iOS 9 ad iOS 10

Una subdola differenza nel comportamento delle notifiche locali fra iOS 9 e iOS 10 è come viene gestita una notifica la cui proprietà fireDate è impostata ad una data nel passato.

In iOS 9 semplicemente questa notifica veniva ignorata, mentre in iOS 10 viene lanciata immediatamente (probabilmente perché il sistema pensa che adesso sia il momento più vicino possibile alla data ormai passata).

Per cui, prima di impostare una fireDate ad un oggetto UILocalNotification è bene controllare che

1
[fireDate timeIntervalSinceNow] > 0
[fireDate timeIntervalSinceNow] > 0

ovvero che la data sia nel futuro.

The data couldn’t be read because it isn’t in the correct format: ecco come validare un file .plist

Xcode permette di modificare un plist anche in vista “Source Code”, molto comoda per modifiche massicce. Però quando si commette un errore e la sintassi non è più quella corretta, Xcode avvisa solo per il formato non è valido, senza alcuna indicazione sulla riga di codice errata: “The data couldn’t be read because it isn’t in the correct format”.

Inoltre non permette di tornare alla vista Property List finché non si è trovato l’errore.

Per poter validare un plist e trovare gli errori allora basta aprire il Terminale, spostarsi nella cartella del file plist e digitare

1
plutil file-name.plist
plutil file-name.plist

Questo restituirà l’elenco degli errori trovati (es: Encountered misformatted real on line 539) oppure restituirà OK.

Preview dell’Autolayout

Fondamentale per l’uso e l’apprendimento dell’Autolayout è la Preview. Ecco la procedura per attivarla:

  1. Apri uno Storyboard.
  2. Apri l’Assistant Editor
  3. Nell’Assistant Editor, clicca sul quarto pulsante (quello che solitamente dice Manual/Automatic/ecc.).
  4. Scegli “Preview”, in fondo all’elenco.
  5. Ora in basso a destra si può scegliere i dispositivi su cui mostrare la Preview.

Animare il cambiamento di una vista

Questa tecnica è utilizzabile sia per creare dissolvenze in uno slideshow di UIImage che per animare la variazione di UI in una UIView.

1
2
3
4
5
6
7
8
/* qui il codice che modifica la vista */
 
CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
 
[aView.layer addAnimation:transition forKey:nil];
/* qui il codice che modifica la vista */

CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;

[aView.layer addAnimation:transition forKey:nil];

Si può aggiungere un .subtype, ad esempio se si vuole far scorrere la vista e decidere la direzione:

1
2
3
4
5
CATransition *transition = [CATransition animation];
transition.duration = .2f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromLeft;
CATransition *transition = [CATransition animation];
transition.duration = .2f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromLeft;

(fonte)

Xcode: Autoincrement Build number

Come distinguere in maniera certa una compilazione da un altra? Come sapere, indipendentemente dalla data, quale archivio per l’invio ad Apple è stato creato prima o dopo? È sufficiente utilizzare il Build number, nei settings del progetto in Xcode, appena sotto il Version number. Però modificarlo ogni volta a mano è fastidiosissimo.

Ecco allora che possiamo utilizzare il comodissimo script di sekati:

1
2
3
4
5
6
7
8
9
10
11
12
13
# xcode-build-bump.sh
# @desc Auto-increment the build number every time the project is run. 
# @usage
# 1. Select: your Target in Xcode
# 2. Select: Build Phases Tab
# 3. Select: Add Build Phase -> Add Run Script
# 4. Paste code below in to new "Run Script" section
# 5. Drag the "Run Script" below "Link Binaries With Libraries"
# 6. Insure that your starting build number is set to a whole integer and not a float (e.g. 1, not 1.0)
 
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
# xcode-build-bump.sh
# @desc Auto-increment the build number every time the project is run. 
# @usage
# 1. Select: your Target in Xcode
# 2. Select: Build Phases Tab
# 3. Select: Add Build Phase -> Add Run Script
# 4. Paste code below in to new "Run Script" section
# 5. Drag the "Run Script" below "Link Binaries With Libraries"
# 6. Insure that your starting build number is set to a whole integer and not a float (e.g. 1, not 1.0)

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"

In pratica si aggiungono e ultime tre righe ad una nuova Build Phase (si crea cliccando sul + in alto a sinistra). L’autore consigli di spostare questa nuova fase appena sotto “Link Binaries With Libraries”, ovvero appena sotto i framework.

Se il numero di Build è un numero intero, questo viene incrementato ogni volta che si lancia il comando Build o Run, sia per il Simulatore che per un Device, e ogni volta che si archivia per inviare l’app ad Apple.

Comodissimo.

Creare una immagine a partire da una mappa

Le funzioni di Quartz sono veramente molto utili perché ci permettono di creare delle immagini e inserirle nell’interfaccia in maniera molto semplice ed efficace. Se però dobbiamo fare il passaggio inverso, ovvero ottenere una immagine a partire dall’interfaccia, come dobbiamo procedere?

In realtà questo è ancora più semplice e, se ad esempio stiamo parlando di un mapView , possiamo usare il seguente codice:

1
2
3
4
UIGraphicsBeginImageContextWithOptions(mapView.bounds.size, NO, 0.0f);
    [mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *mapImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
UIGraphicsBeginImageContextWithOptions(mapView.bounds.size, NO, 0.0f);
    [mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *mapImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

dove assegnamo al contex il render di un layer, e poi usiamo il contex per generare una UIImage. Tutto molto semplice.

Creare una MKAnnotation

MKAnnotation non è una classe, ma è un protocollo a cui deve aderire la classe che andremo a realizzare per visualizzare l’annotazione sulla mappa.

Per questo dobbiamo aggiungere una nuova coppia di file al progetto creando la classe (ad esempio) MyAnnotation. Il file di intestazione e implementazione saranno qualcosa di simile a quanto segue:

1
2
3
4
5
6
7
@interface MyAnnotation : NSObject<MKAnnotation> {
    CLLocationCoordinate2D coordinate;
}
 
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
 
- (id) initWithCoordinate:(CLLocationCoordinate2D)coord;
@interface MyAnnotation : NSObject<MKAnnotation> {
    CLLocationCoordinate2D coordinate;
}

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

- (id) initWithCoordinate:(CLLocationCoordinate2D)coord;

e

1
2
3
4
5
- (id) initWithCoordinate:(CLLocationCoordinate2D)coord
{
    coordinate = coord;
    return self;
}
- (id) initWithCoordinate:(CLLocationCoordinate2D)coord
{
    coordinate = coord;
    return self;
}

Poi sarà sufficiente aggiungere l’annotazione alla mappa:

1
2
3
MyAnnotation * annotation = [[MyAnnotation alloc] initWithCoordinate:coordinate];
 
[self.mapView addAnnotation:annotation];
MyAnnotation * annotation = [[MyAnnotation alloc] initWithCoordinate:coordinate];

[self.mapView addAnnotation:annotation];

Se si vogliono anche titolo e sottotitolo nel callout dell’annotazione, sarà sufficiente aggiungere le proprietà title e subtitle.

Aggiungere una cartella (es. di file HTML) senza perdere la struttura di sottocartelle

Chi ha voluto inserire una cartella di file HTML all’interno di un progetto Xcode si sarà presto accorto che i file vengono trattati come se fossero tutti dentro la cartella principale, e non distribuiti nelle eventuali sottocartelle. Questo crea problemi, ad esempio, nel linkare i file immagine nel file HTML (che andrebbe modificato ad hoc). Ma non solo.

Per ovviare a questo inconveniente è sufficiente ricordarsi di importare la cartella scegliendo l’opzione “Create folder references for any added folders ” (pur con l’opzione Copy items into destination group’s folder (if needed)” attivata).