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.

Comunicare con un UIContainerViewController

Gli UIContainerViewController sono dei contenitori utilissimi per separare un’interfaccia grafica in parti più piccole e meglio gestibili. Un’enorme semplificazione si può avere nell’uso di una UIScrollView, la cui view contenuta, per essere interamente visualizzabile nello Storyboard, può essere comodo inserirla in una container view.

I problemi nascono quando si vuol fare comunicare il container view con il controller principale che lo contiene. A questo proposito la soluzione più comoda, ma non l’unica, è l’uso dei protocolli. Per uno nemo su come realizzare la struttura del protocollo ecco un utile link.

 

 

Creare un popover: una roadmap

Uno degli elementi d’interfaccia più utilizzati su iPad è il popover, elemento che sostituisce i menu a tendina e che discende spesso da un UIBarButtonItem di una toolbar (anche se è possibile collegarlo a qualsiasi elemento dell’interfaccia tramite il metodo presentPopoverFromRect:).

Per utilizzare al meglio un popover è necessario progettarlo con le seguenti caratteristiche

  1. UIPopoverController dev’essere una proprietà sintetizzata nel viewController, di modo da dismetterlo in qualunque momento senza problemi.
  2. Al popover dev’essere associato un protocollo (vedi qui come fare), per fare in modo che il viewController che ha creato il popover (viewController che sarà il suo delegato) riceva informazioni quando viene toccato un pulsante o simile del popover.
  3. Se il popover contiene una tabella, ma anche in altre situazioni, il viewController relativo potrà autodefinire la propria dimensione, di modo che il popover si regoli di conseguenza. Per questo si usa la proprietà del viewController self.contentSizeForViewInPopover, che è un CGSize.
  4. Al tocco del UIBarButtonItem si associa alla proprietà di tipo UIPopoverController un popover che contiene la vista da mostrare:
    1
    2
    
    myPopoverViewController = [[PopoverViewController alloc] initWithNibName:@"PopoverViewController" bundle:nil];
    popoverController = [[UIPopoverController alloc] initWithContentViewController:PopoverViewController];
    myPopoverViewController = [[PopoverViewController alloc] initWithNibName:@"PopoverViewController" bundle:nil];
    popoverController = [[UIPopoverController alloc] initWithContentViewController:PopoverViewController];
  5. Al momento della presentazione del popover si può anche scegliere la direzione della freccia verso cui deve aprirsi:
    1
    
    [popoverController presentPopoverFromBarButtonItem:popoverButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    [popoverController presentPopoverFromBarButtonItem:popoverButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
  6.  Per dismettere il popover si può chiamare semplicemente il seguente metodo
    [popoverController dismissPopoverAnimated:YES];

    ma sfruttando il protocollo creato appositamente, si può chiamare il metodo di protocollo sul delegato e dismettere il popover nell’implementazione di quel metodo. Passando degli argomenti si può decidere di compiere un azione a seconda dell’argomento.

 

Abilitare e disabilitare i pulsanti Avanti e Indietro di un UIWiebView

Quando serve di caricare una pagina HTML in una app, può essere utile abilitare i link e quindi necessario poter andare avanti e indietro nella cronologia di navigazione. Questi movimenti fanno parte del corredo di UIWebView e si chiamano goForward e goBack: possono essere collegati ad dei pulsanti dell’interfaccia.

È utile però disabilitare questi pulsanti quando il movimento non è possibile. Ad esempio non è possibile andare indietro quando si è alla prima pagina HTML aperta, come non è possibile andare avanti quando si è sull’ultima. Per gestire tutto questo è necessario che il ViewController che ospita la WebView implementi il protocollo UIWebViewDelegate e che si implementi in particolare il metodo seguente (fonte):

1
2
3
4
5
6
7
8
9
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
  // Enable or disable back
  [myBackButton setEnabled:[myWebView canGoBack]];
 
  // Enable or disable forward
  [myForwardButton setEnabled:[myWebView canGoForward]];
 
 }
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
  // Enable or disable back
  [myBackButton setEnabled:[myWebView canGoBack]];

  // Enable or disable forward
  [myForwardButton setEnabled:[myWebView canGoForward]];

 }

Grazie ai metodi canGoBack e canGoForward, quindi, i pulsanti vengono abilitati solo quando è possibile usarli. L’interfaccia è ora molto più coerente e intuitiva.

Implementare un Protocollo

Implementare un protocollo può essere una strada molto semplice per fare in modo che un oggetto, che non è in grado di compiere direttamente una azione, possa delegare qualche altro oggetto per compierla. Tale oggetto delegante dovrà quindi dichiarare un protocollo e i suoi metodi, mentre il delegato dovrà dichiarare di essere conforme al protocollo, implementandone i metodi.

Se su una app per iPad, giusto per fare un esempio, un popover permette di settare una variabile nella view che lo ospita, allora possiamo dichiarare un protocollo, un metodo e un delegato nel file di intestazione del popover:

1
2
3
4
5
6
7
8
9
@protocol SetVariableDelegate <NSObject>
 
-(void)setVariable:(int)variable;
 
@end
 
@interface VariableViewController : UITableViewController
 
@property (nonatomic, retain) id<SetVariableDelegate> delegate;
@protocol SetVariableDelegate <NSObject>

-(void)setVariable:(int)variable;

@end

@interface VariableViewController : UITableViewController

@property (nonatomic, retain) id<SetVariableDelegate> delegate;

mentre nel file di implementazione faremo in modo che un certo evento lanci il metodo di protocollo sul delegato:

1
[self.delegate setVariable:value];
[self.delegate setVariable:value];

Nella view, invece, dovremo dichiarare che questa è conforme al protocollo:

1
@interface ViewController : UIViewController <SetVariableDelegate>
@interface ViewController : UIViewController <SetVariableDelegate>

avendo cura di importare la classe (anche se è facile che sia già stata importata per altri motivi), e nel file .m implementare il metodo di protocollo

1
2
3
4
-(void)setVariable:(int)variable{
    //fare qualcosa con variable
 
}
-(void)setVariable:(int)variable{
    //fare qualcosa con variable

}

ricordando, al momento della creazione del popover, di settare tale view come delegato del popover:

1
popover.delegate = self;
popover.delegate = self;

Questo pattern di programmazione ad oggetti è molto utile quando, come nell’esempio del popover, una azione su un oggetto che viene distrutto deve scaturire anche altre azioni sull’oggetto che l’ha creato. Senza i protocolli ci troveremmo nella sgradivo situazione di dover far compiere ad un oggetto defunto una azione non ovviamente non può più compiere.

Quando invece gli oggetti continuano ad esistere, il protocollo è utile ad esempio per delegare un controller nell’impostazione di un oggetto, come nel caso di una UITableView che può delegare un UIViewController che la contiene a reagire al tocco di una riga (UITableViewDelegate) o di definirne il contenuto (UITableViewDataSource). In quest’ultimo caso il metodo di protocollo non è void ma restituisce un valore, ad esempio un intero, usato dalla tabella per sapere quante righe deve contenere, quante righe per ogni sezione eccetera.

N.B.: alcuni metodi del protocollo si possono impostare come obbligatori: chiunque dichiari di essere conforme deve implementarli.