Olen koodaillut tänä keväänä ja kesänä aika paljon iPad- ja iPhone-sovelluksia, lähinnä erilaisia prototyyppejä. Olen tunnistanut ainakin seuraavat kaksi jatkuvasti toistuvaa "patternia", joihin olisi kiva löytää vakioitu ratkaisu.

NSURLConnection: Jonotettu tiedonsiirto

Useimmat sovellukseni rakentuvat siten, että Core Datalla määritellään tietorakenne eli joukko SQLite-tauluja ja niiden kenttiä. Sitten verkosta haetaan JSON-muotoista tietoa ja tallennetaan se kyseisiin tauluihin.

iOS 4 SDK:n vakiotoiminnallisuus mahdollistaa vain yksittäisen taustalla latautuvan downloadin NSURLRequest- ja NSURLConnection-luokilla. Jokaista siirtoa varten pitää tehdä oma delegate-objekti, joka ymmärtää mitä vastaanotetulla tiedolla tehdään. Lisäksi sen pitää osata käynnistää seuraava tiedonsiirto edellisen päätyttyä.

Olisi paljon kätevämpää, jos voisi määritellä vapaamittaisen jonon ladattavia URLeja ja kullekin sitten yksinkertaisen käsittelylogiikan. Jonoon voisi lennossa heittää lisää tavaraa latautumaan sitä mukaa, kun esimerkiksi aiemmin ladatuista JSON-rakenteista huomataan, että tarvitaan myös niihin liittyviä kuvia tai videoita.

Rajapinta voisi toimia esimerkiksi näin:

// Wish for simpler queued NSURLConnections
  • (void)startDownloading { self.queue = [DownloadQueue queue] [queue addDataURL:[NSURL URLWithString:@"http://www.google.com"] target:self onComplete:@selector(googleComplete:data:) onError:nil]; }

  • (void)googleComplete:(DownloadQueue *)queue data:(NSData *)data { // Parse data and load images… [queue addDataURL:[NSURL …] target:self onComplete:@selector(imageComplete:data:) onError:nil]; }

  • (void)imageComplete:(DownloadQueue *)queue data:(NSData *)data { // … }

Core Data: "Hae kaikki" ja "Poista kaikki" -toiminnot

Core Data ei ole mielestäni kovinkaan onnistunut rajapinta. Sen käyttö on työlästä ja monimutkaista. Erityisesti ärsyttää se, että yksittäisen taulun kaikkien rivien poistaminen edellyttää niiden lataamista ensin muistiin ja sitten kunkin poistamista erikseen. Rivien lataaminenkin on aika työlästä, kun NSFetchRequest-koodia pitää kirjoittaa ~10 riviä.

Useimpia käyttötapauksia varten olisi siis kätevää olla yksinkeraisempi rajapinta, jolla voisi hakea tai poistaa taulun kaikki rivit. Rajapinnalle annettaisiin vain taulun nimi (entiteetti), ja mahdollisesti jotain yksinkertaisia järjestys- tai maksimirivimääräehtoja.

Rajapinta voisi toimia esimerkiksi näin:

// Wish for simpler NSFetchRequest
NSFetchRequest *req = [NSFetchRequest requestEntities:@"Article"
                       sortBy:@"pubDate" ascend:NO
                       limit:10 offset:0 context:managedObjectContext];

// Wish for simpler "delete all" API [managedObjectContext deleteAllEntities:@"Article"];