iOS Passbook: an introduction

Passbook è una nuova applicazione presente nell'ultimo rilascio iOS 6 della Apple. In sostanza è una sorta di portafoglio virtuale, che consente di memorizzare coupon, biglietti per il cinema, carte di imbarco, biglietti e altro in modo molto semplice e naturale. I passbook sono interattivi, consentono di visualizzare informazioni sugli oggetti memorizzati, ad esempio il credito residuo, oppure le ultime offerte connesse ad un coupon, o altro. I passbook sono time and location enabled, ovvero è possibile attivarli in prossimità di un punto geografico preciso oppure in un momento ben preciso. Sono memorizzati in locale al device e contengono informazioni essenziali attraverso le quali un'utente può fruire di un oggetto ben preciso. I passbook possono essere aggiornati dinamicamente attraverso il servizio di Push Notification messo a disposizione da Apple, comunicando così variazioni o aggiornamenti in tempo reale. Possono essere distribuiti via email, via web o tramite applicazione.
Per veder decollare del tempo, visto che anche le aziende dovranno supportarlo. L'ultima ad averlo integrato nella propria applicazione è l'app di booking.com….non c'è bisogno che scriva a chi fa riferimento.

Ad ogni modo, quello che a noi interessa è la parte tecnica, vediamo un pò come si fa a creare un Passbook e cosa serve per renderlo interattivo. In questo articolo vedremo una parte di introduzione per farci un'idea. Per creare un'oggetto Passbook è necessario avere:

  • un'identificativo
  • un pass-style
  • informazioni dell'utente
  • immagini, logo e altro
  • location, data e ora

Pass identifier

E' necessario poter distinguere tra un pass e un'altro per questo sono stati introdotti i pass identifier. In generale un'identifier, da diritto all'applicazione di accedere al Passbook tramite la libreria PassKit di iOS.
Esistono diversi tipi di identifier:

Team Identifier

E' un'identificatore stringa di 10 caratteri rilasciato  sul developer portal. Viene utilizzato per recuperare dalla libreria del passbook quello identificato, nel nostro caso, dal teamIdentifier.

 "teamIdentifier" : "DK9N2M2GK6"

Pass Type Identifier

Utilizzato per definire/identificare una classe o una categoria di passbook. Viene rilasciato sul developer portal.

 "passTypeIdentifier" : "it.devme.coupon"

Serial Number Identifier

Utilizzato in congiunzione al pass type identifeer per identificare univocamente e globalmente ciascun passbook. Viene scelto dallo sviluppatore e deve avere una sintassi ben precisa. Vedremo in seguito un caso d'uso che ne chiarisce il funzionamento.  

 "serialNumber" : "B5BD0271-B90B-400D-8344-36A789714CC8"

Come caso d'uso si pensi ad una compagnia aerea che intende distribuire le proprie carte d'imbarco attraverso l'utilizzo dei PassBook. Per ciascuna carta d'imbarco, viene rilasciato un passbook come segue:

 "passTypeIdentifier" : "it.airdevme.boardingpass"

Ciascun passbook deve poter essere univocamente identificato, dal momento che è assegnato a ciascun viaggiatore. Per poter effettuare tale identificazione, si associa al pass type identifier, il serial number, che per semplicità possiamo considerare come:

 "serialNumber" : "001"
 "serialNumber" : "002" 
 "serialNumber" : "003"

Pass Style

Identificato il modo in cui verrà presentato un passbook dal punto di vista grafico. Esistono diverse tipologie di passbook:

  • Coupons
  • Store cards
  • Boarding passes
  • Event tickets
  • Generic

Ogni diverso stile identifica un diverso modello grafico che rappresenterà il passbook sul dispositivo. Ciascun passbook consentirà di inserire le seguenti informazioni per modellare la sua presentazione:

"coupon" : {
     headerFields : ...
     primaryFields : ...
     secondaryFields : ...
     auxilliaryFields : ...
     backFields : ...
     }

Fields

I Fields o informazioni dell'utente, arrichiscono il passbook presentandolo all'utente secondo le informazioni essenziali che lo stesso dovrà presentare. 

"boardingPass": {
    "headerFields" : [ {
		"key": "gate",
		"label": "GATE",
		"value": "82",
		"changeMessage": "Gate changed to %@" 
		}
	],
    "auxiliaryFields" : [ {
		"label" : "DEPARTS",
	}
	],
	"value" : "2012-05-21T12:20:00-07:00",
	"dateStyle" : "PKDateStyleNone",
	"timeStyle" : "PKDateStyleShort"
	"key" : "departs",
   "transitType" : "PKTransitTypeAir"
}

I dati definiti sopra consentono di modellare la carta d'imbarco del nostro esempio. E' facile pensare che le informazioni minime per una carta di imbarco sono il numero del GATE, la data e ora di partenza, eventuli informazioni che devono essere comunicate al viaggiatore.

Color (Immagini logo e altro)

Consente di attribuire un colore al passbook in tutte le sezioni in cui è consentito. Con riferimento al colore di sfondo, colore di primo piano, un colore per l'header, attribuire un logo, un'immagine nell'header, del testo, etc. In generale ci si riferisce a tutte le informazioni di presentazione del passbook.

Location, Data e Ora

E' possibile attribuire ad un Passbook un numero finito di location, ovvero punti di localizzazione, in cui il passbook sarà attivato notificandolo all'utente. Si pensi ad esempio se l'utente si trova in prossimità di un negozio o altro punto di interesse.  E' possibile definire fino a 10 punti di localizzazione nel pass.json. Allo stesso modo è possibile definire una data e un'ora in cui il passbook sarà attivato, proponendo solo in quel momento il passbook all'utente. E' possibile modificare le informazioni sulla localizzazione e sulla data e l'ora anche dopo avere inizializzate. 

"locations" : [
     {
       "longitude" : -122.3748889,
       "latitude" : 37.6189722
     },
     {
       "longitude" : -122.03118,
       "latitude" : 37.33182
     }
   ],
 "relevantDate" : "2011-12-08T13:00-08:00"

L'esempio di sopra inizializza 2 informazioni di localizzazione ed una per data e ora. Nei prossimi articoli vedremo quali servizi è necessario implementare lato server per interagire con i Passbook e quali lato client per gestirne il loro ciclo di vita.

Stay tuned!

Bash port scanner

Stavo facendo qualche esperimento con la shell, e leggendo un pò a caso in rete, ho provato a realizzare un semplice port scanner in bash scripting. Molti degli elementi su Linux funzionano come dei file, ovvero è possibile accedere in lettura per ottenere informazioni e in scrittura per aggiornare il loro stato. Un esempio è il file /dev/tcp/host/port, in particolare scrivendo su questo file speciale viene aperta una connessione TCP verso host:port. Se la scrittura su file ha successo allora la porta viene aperta, altrimenti la porta è chiusa. That's the trick !

for port in {1..65535}; do
  echo >/dev/tcp/devme.it/$port &&
    echo "Yes, I found that port $port is open" ||
    echo "Ops, I found that port $port is closed"
done

Il codice di sopra funziona esattamente come un port scanner con l'unico problema che se la porta risulta chiusa, la shell la rileva dopo circa un paio di minuti, il che rende in pratica poco utilizzabile lo script di sopra. La soluzione che ho trovato in rete è quella di realizzare una sorta di allarme che interrompe lo script se il tempo impiegato per analizzare una porta supera un certo limite, passato come parametro. Riporto il codice per completezza:

alarm() {
  perl -e  '
    eval {
      $SIG{ALRM} = sub { die };
      alarm shift;
      system(@ARGV);
    };
    if ($@) { exit 1 }
   ' "$@";
}

Volendo scrivere un comando completo, il tutto diventa:

scanme() {
  if [[ -z $1 || -z $2 ]]; then
    echo "Usage: $0 <host> <port> <port-range>"
    return
  fi
 
  local host=$1
  local ports=()
  case $2 in
    *-*)
      IFS=- read start end <<< "$2"
      for ((port=start; port <= end; port++)); do
        ports+=($port)
      done
      ;;
    *,*)
      IFS=, read -ra ports <<< "$2"
      ;;
    *)
      ports+=($2)
      ;;
  esac
 
 
  for port in "${ports[@]}"; do
    alarm 1 "echo >/dev/tcp/$host/$port" &&
    echo "Yes, I found that port $port is open" ||
    echo "Ops, I found that port $port is closed"
  done
}

Testando il comando di sopra si ha: scanme devme.it 80-92

#$> scan scanme 80-92 
Yes, I found that port 80 is open
Ops, I found that port 81 is closed
Ops, I found that port 82 is closed

Esiste poi un comando di sistema che consente di lanciare un comando con un time limit, timeout. Con questo comando il tutto diventa molto più semplice:

#$> timeout 1 bash -c "echo >/dev/tcp/$host/$port" &&
    echo "Yes, I found that port $port is open" ||
    echo "Ops, I found that port $port is closed"

Stay tuned!

RESTEasy: le chiamate rest in Java

In questo piccolo tutorial vedremo come realizzare una piccola chiamata REST verso un servizio remoto, il tutto realizzato in Java. Ricordiamo che le chiamate REST consentono di invocare servizi remoti tramite il protocollo HTTP.
La libreria che ho utilizzato per il supporto alle chiamate REST è RESTEasy la quale oltre al supporto HTTP fornisce il supporto alle annotation JAX-RS. Vediamo subito come procedere. Intanto, utilizzando il vostro IDE preferito (Eclipse ad esempio) create un nuovo progetto e aggiungete le seguente librerie nel build path: 

libraries

Alcune di queste non sono essenziali per la creazione del servizio, ma vi consiglio comunque di lasciarle in modo tale da avere supporto a future implementazioni. Il progetto che sono andato a creare è J2EE installato all’interno di tomcat. Ogni servizio verrà testato da una unit test presente all’interno del progetto stesso, così da verificare la correttezza del servizio. Quindi si parte con la configurazione del nostro web descriptor in modo da configurare il nostro contesto: 

<?xml version="1.0" encoding="UTF-8"?>
 
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 
    <display-name>resteasy</display-name>
 
    <listener>
        <listener-class>
            org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
        </listener-class>
    </listener>
 
    <servlet>
        <servlet-name>drest</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>drest</servlet-name>
        <url-pattern>/restful-services/*</url-pattern>
    </servlet-mapping>
 
    <context-param>
         <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>    
    </context-param>
 
 
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/restful-services</param-value>
    </context-param>
 
</web-app>

Fatto questo procediamo con la definizione del servizio. Una premessa fondamentale da fare è la seguente: la creazione di un servizio REST richiede una fase di progettazione attenta e puntuale, in cui molti aspetti devono essere tenuti in considerazione e risolti nel migliore dei modi. L’accesso al servizio, l’autenticazione, l’invio dei dati in input e la restituzione del risultato sono tutti aspetti che fanno parte della progettazione di un servizio. Ciò detto, nel nostro esempio, non considereremo la fase di progettazione in tutti i suoi punti, ma procederemo con la creazione di un servizio a scopo di esempio. Definiamo quindi la classe contenitore del nostro servizio attraverso l’utilizzo delle annotation:

@Path("/devmeservice")
public class DevMeService {
 
	@GET
    @Path("/v1/passes/{pass_type_id}/{device_id}")
    @Produces("text/plain")
    public Response getPassLatestVersion(@HeaderParam("Authorization") String authorization,
					   @PathParam("pass_type_id")String pass_type_id,
					   @PathParam("serial_number")String serial_number){
 
		String auth_token = null;
		if (!authorization.matches("^ApplePass.*")) {
			return Response.status(HttpStatus.SC_FORBIDDEN).build();
		}
		String [] items = authorization.split(" ");
		if (items.length!=2) {
			return Response.status(HttpStatus.SC_FORBIDDEN).build();
		}
 
		auth_token = items[1];
 
		String sql = "SELECT * " +
			 "FROM passes " +
			 "WHERE serial_number = ? AND authentication_token = ? LIMIT 1";
		DBHandle dbhandle = DBHandle.getInstance();
		try {
			PreparedStatement ps = dbhandle.getPreparedStatement(sql);
			ps.setString(1, serial_number);
			ps.setString(2, pass_type_id);
			ResultSet rs = ps.executeQuery();
			if (rs.next()) {
				String pass = readFile(/* PASSES ROOT PATH */"/data/passes/"+serial_number+"/pass.json");
 
			}else {
				return Response.status(HttpStatus.SC_UNAUTHORIZED).build();
			}
		} catch (SQLException e) {
			log.error("Error while registering new device.", e);
			return Response.status(HttpStatus.SC_SERVICE_UNAVAILABLE).build();
		} finally {
			dbhandle.close();
		}
		return null;
    }
 
}

Il metodo di sopra restituisce l’ultima versione di un pass (Passbook) associato ad un particolare dispositivo, sulla base di un codice di autorizzazione concesso al client e dei dati associato al pass stesso. Il metodo verifica prima se il client è autorizzato all’accesso al servizio e successivamente tenta di recuperare le informazioni associate al pass e quindi di restituirlo in output.
Si noti l’utilizzo delle annotation in testa alla classe e in testa al nostro metodo, la prima definizione il nome del servizio che dovrà essere invocato, una sorta di base url. Le seconde annotation definiscono il metodo HTTP che viene utilizzato per l’invocazione del metodo, il percorso del servizio ed infine il mime type della risposta fornita dal metodo. Invocando il servizio con un client HTTP saremo in grado di ottenere la risposta da elaborare localmente.

Nei prossimi articoli tratteremo altri contesti in cui utilizzare le chiamate REST, come i Passbook recentemente introdotti dalla Apple come prossima release in iOS6.

Stay tuned!

Autenticazione facebook: la guida definitiva

logo_facebookSalve a tutti, negli ultimi tempi mi sto divertendo con diverse tecnologie, tra cui le app facebook. In realtà, il progetto ha richiesto lo sviluppo di un’applicazione facebook relativamente semplice, in cui il punto centrale è costituito dalla app request, ovvero le notifiche inviate all’utente dall’applicazione in uso dall’utente, una sorta di notifiche Push iOS style.
Al netto di questa cosa, ho trovato difficoltà nell’implementare il meccanismo di autenticazione richiesto da facebook, ma non perché lo stesso sia difficile, ma semplicemente perché sul sito ufficiale è molto confusa la spiegazione delle API open graph 2, e poi non ho trovato nessuna guida o tutorial che ne descrivesse l’utilizzo. Per questo motivo voglio condividere l’implementazione del meccanismo di autenticazione che ho realizzato all’interno della mia applicazione.

Cominciamo col dire che il back-end dell’applicazione è Java (strano eh!), nello specifico ho utilizzato delle API restFB, che consentono l’interazione con i servizi REST messi a disposizione da facebook. L’applicazione Java utilizza le servlet per interagire con l’utente, quindi in sostanza è un’applicazione web. Per poter utilizzare i servizi REST di facebook è necessario avere a disposizione un access-token, una chiave che consente di identificare l’entità che sta effettuando la richiesta e se la stessa possiede i privilegi per poterla invocare.

Di seguito la procedura per ottenere un access token:

1. https://graph.facebook.com/oauth/authorize?client_id=FACEBOOK_APP_ID&redirect_uri=REDIRECT_URL

2. https://graph.facebook.com/oauth/access_token?client_id=FACEBOOK_APP_ID&redirect_uri=REDIRECT_URL&code=CODE&
client_secret=APP_SECRET

3. Risposta con access token. 

Si parte con una richiesta HTTP all’indirizzo di cui al punto 1, fornendo come parametro la FACEBOOK_APP_ID, ovvero l’id dell’applicazione facebook creata ed un REDIRECT_URL, ovvero un indirizzo di rimando a cui verrà restituita una response contenente un codice, CODE. Lo stesso CODE, dovrà essere fornito come parametro all’indirizzo di cui al punto 2, assieme al FACEBOOK_APP_ID e di nuovo un REDIRECT_URL. Infine, a quest’ultimo verrà restituito una response contenente l’access token, come valore del primo parametro presente nell’URL.

Il punto centrale dell’applicazione Java web è costituito da una servlet filter, la quale viene invocata ogni qual volta si tenta di accedere ad una risorsa dall’applicazione facebook. La filter verifica che sia presente in sessione l’access token, il quale viene messo lì per ovvi motivi di comodità, non appena viene recuperato dalla procedura di autenticazione. Di seguito il codice della servlet filter:

 

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    HttpSession session = httpRequest.getSession();
 
    if (session.getAttribute(FacebookAuthConfig.OAUTH_TOKEN)==null) {
            FacebookAuthConfig facebookConfig = session.getFacebookConfiguration();
 
            String redirectURL = httpRequest.getRequestURL().toString();
            String code = StringUtils.noNullAndTrim(request.getParameter("code"));
            if (code.length()==0) {
                String tokenReqUrl = "https://graph.facebook.com/oauth/authorize?client_id="+facebookConfig.getAppID()+
                                     "&redirect_uri="+redirectURL;
                httpResponse.sendRedirect(tokenReqUrl);
                return;
            }
 
            String tokenUrl = "https://graph.facebook.com/oauth/access_token?client_id="+facebookConfig.getAppID()+
                             "&redirect_uri="+redirectURL+"&code="+code+"&client_secret="+facebookConfig.getAppSecret();
 
            DefaultWebRequestor webRequestor = new DefaultWebRequestor();
            Response fbresponse = webRequestor.executeGet(tokenUrl);
            String rawAccessToken = new String(fbresponse.getBody());
 
            String accessToken;
            if (rawAccessToken.indexOf("&") > -1) {
                rawAccessToken = rawAccessToken.split("&")[0];
            }
            accessToken = rawAccessToken.split("=")[1];
            session.setAttribute(FacebookAuthConfig.OAUTH_TOKEN, accessToken);
            User user = null;
 
            FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
            int attempt = 0;
            do {
                attempt++;
                log.info("* Fetching single objects *");
                try {
                    user = facebookClient.fetchObject("me", User.class);
                    logger.info("User name: " + user.getName());
                } catch (Exception e) {
                     if (attempt==1) {
                        log.warn("Error while quering data to Facebook service. Try again..");
                        continue;
                     } else {
                        log.info("Request error. Can't retrieve data from facebook service.");
                        httpResponse.sendRedirect(errorPage);
                        return;	
                    }
                }
                break;
            } while (true);
 
            session.setAttribute(FACEBOOK_USER_OBJ, user);
            session.setAttribute(OAUTH_TOKEN, accessToken);                    
    }
}

 La prima richiesta HTTP viene invocata per ottenere il CODE da rimandare come parametro nella seconda richiesta HTTP, si noti che nella prima richiesta, il REDIRECT_URL coincide con la stessa risorsa invocata. In questo modo, alla risposta in cui è presente il parametro CODE, è possibile procedere e quindi invocare la seconda richiesta. Quest’ultima viene invocata utilizzando le restFB API, ottenendo quindi la risposta raw direttamente nel body della response. Da lì viene estratta e resa disponibile in sessione. Successivamente viene eseguita una chiamata al servizio REST di facebook per ottenere informazioni riguardo l’utente che ha invocato la risorsa, e se la chiamata va a buon fine, viene aggiunto in sessione l’oggetto User messo a disposizione dalle restFB API. 

That’s all. Stay connected !

Objective-C 2.0 – Direttive del compilatore

learn-objective-cSono alle prese con lo sviluppo di un’app per iPhone e siccome mi trovo a dover utilizzare, per forza di cose, le direttive messe a disposizione dal linguaggio, ho pensato che può essere utile avere una lista che le elenca e che ne spiega il significato. Ho trovato anche un post in rete molto interessante che in pratica fa la stessa cosa, e quindi ne approfitto per diffondere anche io nel panorama italiano.

Let’s go !

@class

Dichiara una classe senza dover utilizzare l’istruzione import con il relativo file header. Viene utilizzato per le class forward declaration.

@class DevMeClass;

@protocol @required @optional @end

Definisce l’inizio della dichiarazione di un protocol. Opzionalmente può dichiarare altri protocol ai quali è conforme come segue:

@protocol DevMeProtocol

 

  • @required: dichiara i metodi come metodi required.
  • @optional: dichiara i metodi come metodi optional. La classe che implementa il protocollo può decidere se implementare o no il metodo opzionale. Le classi che fanno uso del protocollo devono verificare che il metodo opzionale esista prima di utilizzarlo.
    [object respondsToSelector:@selector(optionalProtocolMethod)];
  • @end: dichiara la fine del protocollo.

@interface @public @package @protected @private @property @end

Definisce l’inizio di una classe o category.

Dichiarazione di una classe.

Le classi in Objective-C devono derivare direttamente o indirettamente dalla classe NSObject. La direttiva @interface per la dichiarazione di una classe può opzionalmente dichiarare che la classe è conforme ad altri protocolli.

@interface DevMeClass : DevMeSuperClass <DMProtocol, anotherDMProtocol> {
  // instance variables can be
@public
@package
@protected
@private
}
 
// property declarations
@property (atomic, readwrite, assign) id aProperty;
 
// public instance and/or class method declarations
@end

Dichiarazione di una category

La direttiva @interface non può aggiungere variabili d’istanza ma può opzionalmente dichiarare la conformità ad altri protocolli.

@interface DevMeClass (CategoryName) <DMProtocol, anotherDMProtocol>
 
// property declarations
@property (atomic, readwrite, assign) id dmProperty;
 
// method declarations
@end

Direttive

  • @public: dichiara la variabile d’istanza pubblica. Le varibili pubbliche possono essere lette o modificate con la notazione punto
    devme->bestBlog = true;
  • @package: dichiara la variabile d’istanza pubblica all’interno del framework che definisce la classe ma privata all’esterno.Funziona sui sistemi a 64 bit, su quelli a 32 bit si comporta esattamente come @public.
  • @protected: dichiara la variabile d’istanza protetta e quindi accessibile solo dalla classe che la definisce e dalle sue eventuali derivate.
  • @private: dichiara la variabile d’istanza privata e quindi accessibile solo dalla classe che la definisce.
  • @property: dichiara una proprietà la quale può essere accessibile con la notazione punto. Può essere eseguita dalle specialio parole chiave che ne definiscono l’esatto comportamento. Possono essere:
    • readwrite (default), readonly). Genera il getter e il setter (readwrite), solo il getter ((readonly).
    • assign (default), retain, copy. Si applica solo alle proprietà per cui è possibile effetuare un cast sul tipo id. assign, assegna il valore passato; retain, invia un release alla variabile d’istanza, invia retain al nuovo oggetto e assegna l’oggetto retained alla variabile d’istanza; copy invia un release alla varibile d’istanza, invia copy al nuovo oggetto e assegna l’oggetto copiato alla variabile d’istanza. Negli ultimi casi si è responsabili della deallocazione dell’oggetto.
    • atomic(default), non atomic. Le proprietà atomic sono thread-safe mentre le non-atomic possono essere accedute simultaneamente. Le non atomic sono pià veloci delle atomic e spesso usate nelle applicazione single thread.
    • weak (default), strong. Sono disponibili se la funzionalità ARC (automatic reference counting) è abilitata. La chiave strong è sinonimo di retain, mentre weak è sinonimo di assign.
  • @end: dichiara la fine della dichiarazione dell’interfaccia.

 

@throw @try @catch @finally

Vengono utilizzate per la gestione delle eccezioni.

@try {
    // code that might throw an exception &hellip; like this one:
    NSException *exception = 
        [NSException exceptionWithName:@"DevMeException"
                                reason:@"Test exception!"
                              userInfo:nil];
    @throw exception;
}
@catch (CustomException *ce) {
    // handling ...
}
@catch (NSException *ne) {
    // generic NSException handling ...
 
    // to simply re-throw the caught exception in a catch block:
    @throw;
}
@finally  {
    // after try or catch
}

@synchronized

Asscirua che il codice presente all’interno del blocco può essere disponibile solo ad un thread alla volta.

-(void) syncMethod:(id)object {
   @synchronized(object) {
      // code that works with locked object 
   }
}

@autoreleasepool

Nelle applicazioni in cui è abilitato ARC (Automatic Reference Counting) è necessario usare @autoreleasepool al posto di NSAutoreleasePool. Non bisognerebbe dichiarare una variabile all’interno di un blocco @autoreleasepool e continuare ad usarla dopo il blocco.

-(void) dmMethod {
    @autoreleasepool {
        // code that creates a large number of temporary objects
    }
}

@encode

Restituisce il carattere stringa della codifica di un tipo.

-(void) encMethod {
    char *enc1 = @encode(int);                 // enc1 = "i"
    char *enc2 = @encode(id);                  // enc2 = "@"
    char *enc3 = @encode(@selector(aMethod));  // enc3 = ":"
 
    // practical example:
    CGRect rect = CGRectMake(0, 0, 100, 100);
    NSValue *v = [NSValue value:&rect withObjCType:@encode(CGRect)];
}

@compatibility_alias

Consente di generare un alias per una classe. Il primo parametro è il nome dell’alias della classe, il quale può anche non esistere. Il secondo parametro è il nome della classe. a cui l’alias fa riferimento.

@compatibility_alias AliasClassName ExistingClassName

@string

Dichiara un oggetto NSString. Per tale oggetto non è necessario gestirne la memoria.

-(void) devmeMethod {
    NSString* str = @"Ciao questo &egrave; il blog di devme.";
    NSUInteger strLength = [@"Hello world!" length];
}

The end

Siamo giunti alla fine….per ora naturalmente. Sentitevi liberi di comunicare eventuali errori delle direttive. Nel frattempo, direttamente dal blog da cui ho tratto ispirazione, trovate la stessa lista in pdf ;) .

Stay tuned!

WordPress Themes