One thing that I love about Obj-C and Cocoa is how seamlessly Apple is introducing funcionalities to take advantage of multicore devices.
One of the most common things that a dev does by hourly basis is enumerate a collection.
In Obj-C we can takle this with different approaches:
1 – old plain C for/while loops
2 – fast enumeration protocol (the for..in)
3 – Create an NSEnumerator object from the collection
4 – Use enumeration methods declared in the object interface

The 4th approach is present in almost each kind of collections and one of its methods is the

- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, BOOL *stop))block

The opts parameter is a bit mask where we can pass this really interesting option:

NSEnumerationConcurrent

As the name states this makes the enumeration process a concurrent task and it’s a pleasure to see in instruments the 2 cores working all togheter. There is one caveat as stated by Apple engineers “the code of the block must be safe against concurrent invocation”.

One other stuff that I really love is the way we can help thread safety using blocks.
Recently for a social-instagram-like app I needed to use extensively the AFNetworking library.
To take trace of the networking operation created by each view controller I created a sort of register of the living connection.
The problem in this scenario is the async nature of the process related to the networking tasks. After adding an operation to the register, is impossible to know when it will be  finished (and consequently removed from the register) and this could happen while adding another one the register. We need to put things in order.

To help us we can use a thread locking mechanism,  I’ve found really uselfull the dispatch_barrier mechanism that has less overhead compared to an exclusive lock.

First we need to create our concurrent queue.
In the reading method we create a synch block that waits for the reading to end, if more cores are avalaible more reading request can occur, in the writing method we use a barrier to be sure that no other code has access until the writing finishes. Since GCD queue are executed in first in – first out order we can guarantee that the block would be executed in the same order we have requested.
As you can see from the picture (taken from the book Effective Obj-C 2.0) while the writing block is executing no reading (or writing) can happen.

Read-Write process

Read-Write process

In code is pretty much something like that.

First we create a our concurrent queue

syncQueue = dispatch_queue_create("it.shootshare.registeroperation", DISPATCH_QUEUE_CONCURRENT);

Then we override our properties:

- (NSString*) name {
  NSString * __block aName = nil;
  dispatch_sync(syncQueue, ^{
     aName = _name;
  });
  return aName;
}

- (void) setName:(NSString*)aName {
   dispatch_barrier_async(syncQueue, ^{
     _name = aName;
  });
}

Di recente ho dovuto “smanettare” per un bel po’ di tempo sulle UITableView  con contenuto statico.

Cosa sono le UITableView statiche?

Dal punto di visto dell’utilità sono eccezionali perché in pochissimo tempo, tramite l’editor degli storyboard consentono di creare una lista di celle fissa, statica, nel senso che non può cambiare a runtime (anche se non è completamente esatto perché certi comportamenti possono essere sovrascritti). Ciò comporta il non dover implementare i metodi di data source (UITableViewDataSource).

Lo svantaggio è che non sono celle riutilizzabili, quindi un uso massiccio impatta in maniera negativa sulle performance. Devono essere, pertanto, usate quando il numero di elementi in una UITableView è basso.

Si pensi, ad esempio, di dover comporre una lista di attributi che descrivono l’articolo di un negozio, come:

  • data inserimento articolo
  • pezzi a magazzino
  • costo articolo
  • etc…

Per un requisito del genere una table view statica è un ottimo candidato per creare un’interfaccia di questo tipo. Essa apporta maggiori vantaggi rispetto ad una classica view con label e campi di testo.

Perché ? :

  1. le UITableView sono un elemento estremamente “mantenibile”: se volessi aggiungere una voce mi basterebbe aggiungere un’altra row
  2. le UITableView ereditano dalle  UIScrollView posso anche non preoccuparmi delle diverse dimensioni di schermo
  3. non c’è bisogno di impazzire dietro ad autolayout
  4. non è necessario implementare i metodi di datasource
  5. se l’ interfaccia presenta dei campi da occultare in alcuni casi posso semplicemente dire alla tableview che a quell’index path per quel specifico caso l’altezza è 0 (solo per UITableViewController)

Mi occuperò, dunque, proprio dell’altezza delle UITableViewCell. Uno degli ostacoli forse più difficili da superare nell’utilizzo di queste è riuscire a creare delle celle di altezza variabile che si adattino al contenuto. Per capirci, è sufficiente pensare a quelle di what’s app o dell’applicazione messaggi.

L’altezza delle UITableViewCell viene infatti calcolata prima che queste vengano create e renderizzate a schermo perché le altezze sono necessarie per calcolare la contentSize della UIScrollView; una soluzione spesso adottata è quella di creare un modello di altezze, ovvero si precalcolano le altezze prima di visualizzare le celle per poi passare questo dato nel metodo – tableView:heightForRowAtIndexPath: . Un’operazione che poteva diventare ancora più complessa nel qual caso le celle fossero state di diverso tipo. Ciò comportava la creazione delle celle nella fase di precalcolo in maniera da realizzare tutti i calcoli necessari e fornire un’altezza corretta.

Si era di fronte al classico “collo di bottiglia”. Su table view, in presenza di un grande numero di righe, si poteva  giungere ad una situazione molto fastidiosa: un blocco momentaneo con un ritardo sul caricamento dell’interfaccia.

iOS7 ha introdotto un nuovo metodo – tableView:estimatedHeightForRowAtIndexPath: che rimanda al momento della visualizzazione il richiamo del metodo – tableView:heightForRowAtIndexPath:.

Sostanzialmente richiede una stima che consenta alla UITableView di potersi dare una contentSize di settare le altezze delle scrollbar etc.

Anche in questo caso ci troviamo di fronte ad uno strumento che dovrebbe essere usato solo in certe occasioni. Infatti, il calcolo dell’altezza rimandato durante il caricamento della cella può creare un lag durante lo scrolling percettibile.

La stima da fornire può essere un numero fisso, magari basato su una media ipotetica dei diversi valori che l’altezza può assumere, oppure può essere un calcolo approssimato molto più veloce di quello più preciso.

Un suggerimento che vale la pena menzionare è il caching dei valori già calcolati delle altezze. Se le celle non subiscono modifiche dopo la loro visualizzazione è inutile ricalcolarne l’altezza ogni volta, basta restituire quella in cache.