SlideShare a Scribd company logo
Taming
Core
Data
CocoaHeads Berlin
Arkadiusz Holko
@arekholko
holko.pl
Taming Core Data by Arek Holko, Macoscope
Core Data
Anyone?
Taming Core Data by Arek Holko, Macoscope
What is
Core
Data?
Core Data is a framework that you use
to manage the model layer objects in
your application.
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
Can
We Do
Better?
Taming Core Data by Arek Holko, Macoscope
A framework that you use to build the
persistence layer in your application.
Taming Core Data by Arek Holko, Macoscope
Example
Taming Core Data by Arek Holko, Macoscope
Core Data
Primer
NSManagedObject
NSManagedObjectContext
Similar to:
» sqlite3 *
» RLMRealm */Realm
TweetList
ViewController
Fetch
class TweetListViewController: UITableViewController {
...
func fetchTweets() {
let application = UIApplication.sharedApplication()
guard let appDelegate = application.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.managedObjectContext
}
}
Fetch ?
class TweetListViewController: UITableViewController {
...
func fetchTweets() {
let application = UIApplication.sharedApplication()
guard let appDelegate = application.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "ManagedTweet")
fetchRequest.predicate = NSPredicate(format: "homeTimeline != NULL")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "identifier",
ascending: false)]
}
}
Fetch ?!
class TweetListViewController: UITableViewController {
...
func fetchTweets() {
let application = UIApplication.sharedApplication()
guard let appDelegate = application.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "ManagedTweet")
fetchRequest.predicate = NSPredicate(format: "homeTimeline != NULL")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "identifier",
ascending: false)]
let results = try? managedObjectContext.executeFetchRequest(fetchRequest)
if let managedObjects = results as? [NSManagedObject] {
data = managedObjects
}
}
}
data property
class TweetListViewController: UITableViewController {
...
var data: [ManagedTweet] = [] {
didSet {
tableView.reloadData()
}
}
}
cellForRowAtIndexPath:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier,
forIndexPath: indexPath) as! TweetTableViewCell
}
cellForRowAtIndexPath:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier,
forIndexPath: indexPath) as! TweetTableViewCell
let tweet = data[indexPath.row]
}
cellForRowAtIndexPath:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier,
forIndexPath: indexPath) as! TweetTableViewCell
let tweet = data[indexPath.row]
if let text = tweet.valueForKey("text") as? String {
cell.multilineTextLabel?.text = text
}
// set up other views
return cell
}
Taming Core Data by Arek Holko, Macoscope
9 Steps
Step #1
–
Setup
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
The app delegate works alongside the
app object to ensure your app interacts
properly with the system and with
other apps.
— Apple
PersistentStack
class PersistentStack {
let managedObjectContext: NSManagedObjectContext
init(storeType: String) {
...
}
}
AppDelegate now
class AppDelegate: UIResponder, UIApplicationDelegate {
let persistentStack = PersistentStack(NSSQLiteStoreType)
...
}
Step #2
–
Accessing
NSManagedObjectContext
The Easy Way
class TweetListViewController: UITableViewController {
let managedObjectContext: NSManagedObjectContext
init() {
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
managedObjectContext = appDelegate.persistentStack.managedObjectContext
}
super.init(nibName: nil, bundle: nil)
}
}
Singleton
class TweetListViewController: UITableViewController {
let managedObjectContext: NSManagedObjectContext
init() {
managedObjectContext = PersistentStack.sharedInstance().managedObjectContext
super.init(nibName: nil, bundle: nil)
}
}
Taming Core Data by Arek Holko, Macoscope
Dependency Injection
class TweetListViewController: UITableViewController {
let managedObjectContext: NSManagedObjectContext
init(managedObjectContext: NSManagedObjectContext) {
self.managedObjectContext = managedObjectContext
super.init(nibName: nil, bundle: nil)
}
}
Step #3
–
NSManagedObject subclass
NSManagedObject with KVC
let tweet: NSManagedObject = data[indexPath.row]
if let text = tweet.valueForKey("text") as? String {
cell.multilineTextLabel?.text = text
}
Subclassed NSManagedObject
let tweet: ManagedTweet = data[indexPath.row]
cell.multilineTextLabel.text = tweet.text
Generators
» Xcode: Editor → Create NSManagedObject subclass...
» mogenerator
class _ManagedTweet: NSManagedObject {
...
// MARK: - Properties
@NSManaged
var identifier: NSNumber
@NSManaged
var text: String
// MARK: - Relationships
@NSManaged
var homeTimeline: ManagedHomeTimeline?
@NSManaged
var user: ManagedUser
}
enum ManagedTweetAttributes: String {
case identifier = "identifier"
case text = "text"
}
enum ManagedTweetRelationships: String {
case homeTimeline = "homeTimeline"
case user = "user"
}
Step #4
–
Who should create NSFetchRequest?
Data Manager?
class DataManager {
}
Taming Core Data by Arek Holko, Macoscope
Repository
class TweetListRepository {
let managedObjectContext: NSManagedObjectContext
init(managedObjectContext: NSManagedObjectContext) {
self.managedObjectContext = managedObjectContext
}
...
}
class TweetListRepository {
...
func performFetch(completion: [ManagedTweet] -> Void) {
let fetchRequest = NSFetchRequest(entityName: ManagedTweet.entityName())
let homeTimelineKey = ManagedTweetRelationships.homeTimeline.rawValue
fetchRequest.predicate = NSPredicate(format: "%@ != NULL",
homeTimelineKey);
let identifierKey = ManagedTweetAttributes.identifier.rawValue
fetchRequest.sortDescriptors = [NSSortDescriptor(key: identifierKey,
ascending: false)]
let results = try? managedObjectContext.executeFetchRequest(fetchRequest)
if let managedTweets = results as? [ManagedTweet] {
completion(managedTweets)
}
}
}
Impact on the view controller
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
repository.performFetch { [weak self] managedTweets -> Void in
self?.data = managedTweets
}
}
NSManagedObjectContext gets hidden from
the view controller
class TweetListViewController: UITableViewController {
let repository: TweetListRepository
init(repository: TweetListRepository) {
self.repository = repository
super.init(nibName: nil, bundle: nil)
}
...
}
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
Data repositories' flow
class ProfileRepository {
let managedObjectContext: NSManagedObjectContext
let profileIdentifier: Int
init(managedObjectContext: NSManagedObjectContext, profileIdentifier: Int) {
self.managedObjectContext = managedObjectContext
self.profileIdentifier = profileIdentifier
}
}
protocol Repository {
var managedObjectContext: NSManagedObjectContext { get }
}
extension ProfileRepository {
convenience init(repository: Repository, profileIdentifier: Int64) {
self.init(managedObjectContext: repository.managedObjectContext,
profileIdentifier: profileIdentifier)
}
}
let profileRepository = ProfileRepository(repository: repository,
profileIdentifier: profileIdentifier)
let viewController = ProfileViewController(repository: profileRepository)
Step #5
–
Networking
protocol Request {
typealias ResultType
var method: Method { get }
var path: String { get }
var parameters: Dictionary<String, String> { get }
func send(completion: (Result<ResultType, NSError> -> Void))
func resultFromJSON(JSON: AnyObject) throws -> ResultType
}
Result: github.com/antitypical/Result
extension Request {
var method: Method { return .GET }
var path: String { return "" }
var parameters: Dictionary<String, String> { return Dictionary() }
}
extension Request {
var method: Method { return .GET }
var path: String { return "" }
var parameters: Dictionary<String, String> { return Dictionary() }
func send(completion: (Result<ResultType, NSError> -> Void)) {
let response = RequestSender().send(self)
do {
let result = try self.resultFromJSON(response)
completion(Result(result))
} catch let nserror as NSError {
completion(Result(error: nserror))
}
}
}
struct Tweet {
let identifier: Int
let text: String
let user: User
}
struct User {
let identifier: Int
let name: String
let profileImageUrl: String?
let screenName: String
}
class TweetListRequest: Request {
typealias ResultType = [Tweet]
var path: String { return "statuses/home_timeline" }
func resultFromJSON(JSON: AnyObject) throws -> [Tweet] {
return try [Tweet].decode(JSONString)
}
}
decode: github.com/Anviking/Decodable
class TweetListImporter {
let managedObjectContext: NSManagedObjectContext
init(managedObjectContext: NSManagedObjectContext) {
self.managedObjectContext = managedObjectContext
}
func importTweets(tweets: [Tweet],
completion: (Result<Bool, NSError> -> Void)) {
...
}
}
Value Type → NSManagedObject
» Objective-C
» Mantle with MTLManagedObjectAdapter
» Swift
» CoreValue, but too powerful
» own solution similar to JSON parsing libraries, such as Argo
or Decodable
Taming Core Data by Arek Holko, Macoscope
Step #6
–
NSFetchedResultsController
!
Problem with
NSFetchedResultsControllerDelegate
optional public func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
Problem with
NSFetchedResultsControllerDelegate
didChangeObject anObject: AnyObject,
TweetListRepository API
class TweetListRepository: Repository {
weak var delegate: NSFetchedResultsControllerDelegate?
var objects: [ManagedTweet] // computed property
}
TweetListRepository API
class TweetListRepository: Repository {
weak var delegate: RepositoryDelegate?
var objects: [ManagedTweet] // computed property
}
Our own delegate
protocol Repository {
func performFetch()
}
protocol RepositoryDelegate: class {
func repository(repository: Repository, didFinishInitialRequestWithResult
result: Result<Bool, NSError>)
func repositoryWillChangeContent(repository: Repository)
func repositoryDidChangeContent(repository: Repository)
func repository(repository: Repository, didInsertRowAtIndexPath indexPath: NSIndexPath)
func repository(repository: Repository, didDeleteRowAtIndexPath indexPath: NSIndexPath)
func repository(repository: Repository, didUpdateRowAtIndexPath indexPath: NSIndexPath)
}
From NSFRCDelegate to RepositoryDelegate
class TweetListRepository: Repository {
// other delegate methods omitted for clarity
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?) {
switch (type) {
case .Insert:
delegate?.repository(self, didInsertRowAtIndexPath: newIndexPath!)
case .Delete:
delegate?.repository(self, didDeleteRowAtIndexPath: indexPath!)
case .Update:
delegate?.repository(self, didUpdateRowAtIndexPath: indexPath!)
case .Move:
// consider adding separate update callback
delegate?.repository(self, didDeleteRowAtIndexPath: indexPath!)
delegate?.repository(self, didInsertRowAtIndexPath: newIndexPath!)
}
}
}
Reacting to changes
extension TweetListViewController: RepositoryDelegate {
// some methods omitted
func repository(repository: Repository, didInsertRowAtIndexPath indexPath: NSIndexPath) {
tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func repository(repository: Repository, didDeleteRowAtIndexPath indexPath: NSIndexPath) {
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func repository(repository: Repository, didUpdateRowAtIndexPath indexPath: NSIndexPath) {
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
}
NSFetchedResultsController
Not only for
table/collection views
ProfileRepository
protocol SingleElementRepository {
func performFetch()
}
protocol SingleElementRepositoryDelegate: class {
func singleElementRepositoryDidUpdate(repository: SingleElementRepository)
}
class ProfileRepository: SingleElementRepository {
weak var delegate: SingleElementRepositoryDelegate?
var user: User? // computed property
...
}
!
Taming Core Data by Arek Holko, Macoscope
Issues
» mutability
» faulting
» lack of thread safety
Taming Core Data by Arek Holko, Macoscope
Step #7
–
Protocolization
protocol TweetType {
var identifier: Int { get }
var text: String { get }
var user: UserType { get }
}
protocol UserType {
var identifier: Int { get }
var name: String { get }
var profileImageUrl: String? { get }
var screenName: String { get }
}
class TweetListRepository: Repository {
weak var delegate: RepositoryDelegate?
var objects: [TweetType] // computed property
}
Issues
» mutability
» faulting
» lack of thread safety
Taming Core Data by Arek Holko, Macoscope
Step #8
–
Immutable Models
Immutable Core Data ?
!
Those Structs
struct Tweet: TweetType {
let identifier: Int
let text: String
let user: User
}
struct User: UserType {
let identifier: Int
let name: String
let profileImageUrl: String?
let screenName: String
}
class TweetListRepository: Repository {
weak var delegate: RepositoryDelegate?
var objects: [TweetType] {
// non-optimized version
let fetchedObjects = fetchedResultsController.fetchedObjects
return structsFromManagedObjects(fetchedObjects)
}
}
Mutation
func favoriteTweet(tweet: TweetType) {
// modifies corresponding managed object under the hood
}
Issues
» mutability
» faulting
» lack of thread safety
New Issues
» data duplication in memory
» CPU time for conversions (can be in the background)
» possible lack of synchronization
Step #9
–
Modularization
.framework
Package.swift
Summary
Lessons learned
» small classes/structs
» testability
» separation of concerns
Can We
Take This
Even Further?
Taming Core Data by Arek Holko, Macoscope
Thank You!
Questions?
@arekholko
Slides
https://speakerdeck.com/fastred/taming-core-data-cocoaheads
Links (1/2)
» https://www.youtube.com/watch?v=WpkDN78P884
» https://www.destroyallsoftware.com/talks/boundaries
» http://objectsonrails.com/
» http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-
architecture.html
» https://realm.io/news/andy-matuschak-controlling-
complexity/
Links (2/2)
» http://khanlou.com/2015/06/protocol-oriented-networking/
» https://twitter.com/andy_matuschak/status/
560857237640343552
» https://github.com/rentzsch/mogenerator
» https://www.objc.io/issues/13-architecture/viper/
» https://developers.facebooklive.com/videos/525/facebook-
on-ios-inside-the-big-blue-app
Ad

More Related Content

What's hot (19)

Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
Fabio Collini
 
Android architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta IndonesiaAndroid architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta Indonesia
Pratama Nur Wijaya
 
Call Back
Call BackCall Back
Call Back
leminhvuong
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
leminhvuong
 
Java Programming - 08 java threading
Java Programming - 08 java threadingJava Programming - 08 java threading
Java Programming - 08 java threading
Danairat Thanabodithammachari
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... Again
Pedro Vicente
 
Advanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceAdvanced java practical semester 6_computer science
Advanced java practical semester 6_computer science
Niraj Bharambe
 
GKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroid
GDG Korea
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
Mario Fusco
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
Fabio Collini
 
AWS Java SDK @ scale
AWS Java SDK @ scaleAWS Java SDK @ scale
AWS Java SDK @ scale
Tomasz Kowalczewski
 
Basic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time APIBasic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time API
jagriti srivastava
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbron
cymbron
 
Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.
Kuldeep Jain
 
12advanced Swing
12advanced Swing12advanced Swing
12advanced Swing
Adil Jafri
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
Michele Capra
 
Java 7 & 8 New Features
Java 7 & 8 New FeaturesJava 7 & 8 New Features
Java 7 & 8 New Features
Leandro Coutinho
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
WindowsPhoneRocks
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
Savvycom Savvycom
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
Fabio Collini
 
Android architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta IndonesiaAndroid architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta Indonesia
Pratama Nur Wijaya
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
leminhvuong
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... Again
Pedro Vicente
 
Advanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceAdvanced java practical semester 6_computer science
Advanced java practical semester 6_computer science
Niraj Bharambe
 
GKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroid
GDG Korea
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
Mario Fusco
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
Fabio Collini
 
Basic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time APIBasic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time API
jagriti srivastava
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbron
cymbron
 
Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.
Kuldeep Jain
 
12advanced Swing
12advanced Swing12advanced Swing
12advanced Swing
Adil Jafri
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
Michele Capra
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
WindowsPhoneRocks
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
Savvycom Savvycom
 

Similar to Taming Core Data by Arek Holko, Macoscope (20)

比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
javatwo2011
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
Alexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
C.T.Co
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
Tomáš Kypta
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
vhazrati
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
Xebia IT Architects
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
IndicThreads
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
DataArt
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
Fabio Collini
 
The Ring programming language version 1.2 book - Part 5 of 84
The Ring programming language version 1.2 book - Part 5 of 84The Ring programming language version 1.2 book - Part 5 of 84
The Ring programming language version 1.2 book - Part 5 of 84
Mahmoud Samir Fayed
 
Android best practices
Android best practicesAndroid best practices
Android best practices
Jose Manuel Ortega Candel
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
TechWell
 
Session 9 Android Web Services - Part 2.pdf
Session 9 Android Web Services - Part 2.pdfSession 9 Android Web Services - Part 2.pdf
Session 9 Android Web Services - Part 2.pdf
EngmohammedAlzared
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
Giuseppe Filograno
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
Ian Robertson
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
Konstantin Kudryashov
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
Rick Warren
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
Jorge Ortiz
 
How te bring common UI patterns to ADF
How te bring common UI patterns to ADFHow te bring common UI patterns to ADF
How te bring common UI patterns to ADF
Getting value from IoT, Integration and Data Analytics
 
Diifeerences In C#
Diifeerences In C#Diifeerences In C#
Diifeerences In C#
rohit_gupta_mrt
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
javatwo2011
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
Alexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
C.T.Co
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
Tomáš Kypta
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
vhazrati
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
IndicThreads
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
DataArt
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
Fabio Collini
 
The Ring programming language version 1.2 book - Part 5 of 84
The Ring programming language version 1.2 book - Part 5 of 84The Ring programming language version 1.2 book - Part 5 of 84
The Ring programming language version 1.2 book - Part 5 of 84
Mahmoud Samir Fayed
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
TechWell
 
Session 9 Android Web Services - Part 2.pdf
Session 9 Android Web Services - Part 2.pdfSession 9 Android Web Services - Part 2.pdf
Session 9 Android Web Services - Part 2.pdf
EngmohammedAlzared
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
Giuseppe Filograno
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
Ian Robertson
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
Konstantin Kudryashov
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
Rick Warren
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
Jorge Ortiz
 
Ad

Recently uploaded (20)

Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
Into The Box Conference Keynote Day 1 (ITB2025)
Into The Box Conference Keynote Day 1 (ITB2025)Into The Box Conference Keynote Day 1 (ITB2025)
Into The Box Conference Keynote Day 1 (ITB2025)
Ortus Solutions, Corp
 
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Impelsys Inc.
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Role of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered ManufacturingRole of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered Manufacturing
Andrew Leo
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven InsightsAndrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell
 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
Semantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AISemantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AI
artmondano
 
What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...
Vishnu Singh Chundawat
 
AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...
Alan Dix
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
Rusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond SparkRusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond Spark
carlyakerly1
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
Into The Box Conference Keynote Day 1 (ITB2025)
Into The Box Conference Keynote Day 1 (ITB2025)Into The Box Conference Keynote Day 1 (ITB2025)
Into The Box Conference Keynote Day 1 (ITB2025)
Ortus Solutions, Corp
 
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Impelsys Inc.
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Role of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered ManufacturingRole of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered Manufacturing
Andrew Leo
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven InsightsAndrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell
 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
Semantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AISemantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AI
artmondano
 
What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...
Vishnu Singh Chundawat
 
AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything – Talk at Cardiff Metropolitan University, 29th April 2...
Alan Dix
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
Rusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond SparkRusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond Spark
carlyakerly1
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Ad

Taming Core Data by Arek Holko, Macoscope

  • 7. Core Data is a framework that you use to manage the model layer objects in your application.
  • 12. A framework that you use to build the persistence layer in your application.
  • 20. Fetch class TweetListViewController: UITableViewController { ... func fetchTweets() { let application = UIApplication.sharedApplication() guard let appDelegate = application.delegate as? AppDelegate else { return } let managedObjectContext = appDelegate.managedObjectContext } }
  • 21. Fetch ? class TweetListViewController: UITableViewController { ... func fetchTweets() { let application = UIApplication.sharedApplication() guard let appDelegate = application.delegate as? AppDelegate else { return } let managedObjectContext = appDelegate.managedObjectContext let fetchRequest = NSFetchRequest(entityName: "ManagedTweet") fetchRequest.predicate = NSPredicate(format: "homeTimeline != NULL") fetchRequest.sortDescriptors = [NSSortDescriptor(key: "identifier", ascending: false)] } }
  • 22. Fetch ?! class TweetListViewController: UITableViewController { ... func fetchTweets() { let application = UIApplication.sharedApplication() guard let appDelegate = application.delegate as? AppDelegate else { return } let managedObjectContext = appDelegate.managedObjectContext let fetchRequest = NSFetchRequest(entityName: "ManagedTweet") fetchRequest.predicate = NSPredicate(format: "homeTimeline != NULL") fetchRequest.sortDescriptors = [NSSortDescriptor(key: "identifier", ascending: false)] let results = try? managedObjectContext.executeFetchRequest(fetchRequest) if let managedObjects = results as? [NSManagedObject] { data = managedObjects } } }
  • 23. data property class TweetListViewController: UITableViewController { ... var data: [ManagedTweet] = [] { didSet { tableView.reloadData() } } }
  • 24. cellForRowAtIndexPath: override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TweetTableViewCell }
  • 25. cellForRowAtIndexPath: override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TweetTableViewCell let tweet = data[indexPath.row] }
  • 26. cellForRowAtIndexPath: override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TweetTableViewCell let tweet = data[indexPath.row] if let text = tweet.valueForKey("text") as? String { cell.multilineTextLabel?.text = text } // set up other views return cell }
  • 33. The app delegate works alongside the app object to ensure your app interacts properly with the system and with other apps. — Apple
  • 34. PersistentStack class PersistentStack { let managedObjectContext: NSManagedObjectContext init(storeType: String) { ... } }
  • 35. AppDelegate now class AppDelegate: UIResponder, UIApplicationDelegate { let persistentStack = PersistentStack(NSSQLiteStoreType) ... }
  • 37. The Easy Way class TweetListViewController: UITableViewController { let managedObjectContext: NSManagedObjectContext init() { if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate { managedObjectContext = appDelegate.persistentStack.managedObjectContext } super.init(nibName: nil, bundle: nil) } }
  • 38. Singleton class TweetListViewController: UITableViewController { let managedObjectContext: NSManagedObjectContext init() { managedObjectContext = PersistentStack.sharedInstance().managedObjectContext super.init(nibName: nil, bundle: nil) } }
  • 40. Dependency Injection class TweetListViewController: UITableViewController { let managedObjectContext: NSManagedObjectContext init(managedObjectContext: NSManagedObjectContext) { self.managedObjectContext = managedObjectContext super.init(nibName: nil, bundle: nil) } }
  • 42. NSManagedObject with KVC let tweet: NSManagedObject = data[indexPath.row] if let text = tweet.valueForKey("text") as? String { cell.multilineTextLabel?.text = text }
  • 43. Subclassed NSManagedObject let tweet: ManagedTweet = data[indexPath.row] cell.multilineTextLabel.text = tweet.text
  • 44. Generators » Xcode: Editor → Create NSManagedObject subclass... » mogenerator
  • 45. class _ManagedTweet: NSManagedObject { ... // MARK: - Properties @NSManaged var identifier: NSNumber @NSManaged var text: String // MARK: - Relationships @NSManaged var homeTimeline: ManagedHomeTimeline? @NSManaged var user: ManagedUser }
  • 46. enum ManagedTweetAttributes: String { case identifier = "identifier" case text = "text" } enum ManagedTweetRelationships: String { case homeTimeline = "homeTimeline" case user = "user" }
  • 47. Step #4 – Who should create NSFetchRequest?
  • 50. Repository class TweetListRepository { let managedObjectContext: NSManagedObjectContext init(managedObjectContext: NSManagedObjectContext) { self.managedObjectContext = managedObjectContext } ... }
  • 51. class TweetListRepository { ... func performFetch(completion: [ManagedTweet] -> Void) { let fetchRequest = NSFetchRequest(entityName: ManagedTweet.entityName()) let homeTimelineKey = ManagedTweetRelationships.homeTimeline.rawValue fetchRequest.predicate = NSPredicate(format: "%@ != NULL", homeTimelineKey); let identifierKey = ManagedTweetAttributes.identifier.rawValue fetchRequest.sortDescriptors = [NSSortDescriptor(key: identifierKey, ascending: false)] let results = try? managedObjectContext.executeFetchRequest(fetchRequest) if let managedTweets = results as? [ManagedTweet] { completion(managedTweets) } } }
  • 52. Impact on the view controller override func viewDidLoad() { super.viewDidLoad() setupTableView() repository.performFetch { [weak self] managedTweets -> Void in self?.data = managedTweets } }
  • 53. NSManagedObjectContext gets hidden from the view controller class TweetListViewController: UITableViewController { let repository: TweetListRepository init(repository: TweetListRepository) { self.repository = repository super.init(nibName: nil, bundle: nil) } ... }
  • 56. Data repositories' flow class ProfileRepository { let managedObjectContext: NSManagedObjectContext let profileIdentifier: Int init(managedObjectContext: NSManagedObjectContext, profileIdentifier: Int) { self.managedObjectContext = managedObjectContext self.profileIdentifier = profileIdentifier } }
  • 57. protocol Repository { var managedObjectContext: NSManagedObjectContext { get } } extension ProfileRepository { convenience init(repository: Repository, profileIdentifier: Int64) { self.init(managedObjectContext: repository.managedObjectContext, profileIdentifier: profileIdentifier) } } let profileRepository = ProfileRepository(repository: repository, profileIdentifier: profileIdentifier) let viewController = ProfileViewController(repository: profileRepository)
  • 59. protocol Request { typealias ResultType var method: Method { get } var path: String { get } var parameters: Dictionary<String, String> { get } func send(completion: (Result<ResultType, NSError> -> Void)) func resultFromJSON(JSON: AnyObject) throws -> ResultType } Result: github.com/antitypical/Result
  • 60. extension Request { var method: Method { return .GET } var path: String { return "" } var parameters: Dictionary<String, String> { return Dictionary() } }
  • 61. extension Request { var method: Method { return .GET } var path: String { return "" } var parameters: Dictionary<String, String> { return Dictionary() } func send(completion: (Result<ResultType, NSError> -> Void)) { let response = RequestSender().send(self) do { let result = try self.resultFromJSON(response) completion(Result(result)) } catch let nserror as NSError { completion(Result(error: nserror)) } } }
  • 62. struct Tweet { let identifier: Int let text: String let user: User } struct User { let identifier: Int let name: String let profileImageUrl: String? let screenName: String }
  • 63. class TweetListRequest: Request { typealias ResultType = [Tweet] var path: String { return "statuses/home_timeline" } func resultFromJSON(JSON: AnyObject) throws -> [Tweet] { return try [Tweet].decode(JSONString) } } decode: github.com/Anviking/Decodable
  • 64. class TweetListImporter { let managedObjectContext: NSManagedObjectContext init(managedObjectContext: NSManagedObjectContext) { self.managedObjectContext = managedObjectContext } func importTweets(tweets: [Tweet], completion: (Result<Bool, NSError> -> Void)) { ... } }
  • 65. Value Type → NSManagedObject » Objective-C » Mantle with MTLManagedObjectAdapter » Swift » CoreValue, but too powerful » own solution similar to JSON parsing libraries, such as Argo or Decodable
  • 68. Problem with NSFetchedResultsControllerDelegate optional public func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
  • 70. TweetListRepository API class TweetListRepository: Repository { weak var delegate: NSFetchedResultsControllerDelegate? var objects: [ManagedTweet] // computed property }
  • 71. TweetListRepository API class TweetListRepository: Repository { weak var delegate: RepositoryDelegate? var objects: [ManagedTweet] // computed property }
  • 72. Our own delegate protocol Repository { func performFetch() } protocol RepositoryDelegate: class { func repository(repository: Repository, didFinishInitialRequestWithResult result: Result<Bool, NSError>) func repositoryWillChangeContent(repository: Repository) func repositoryDidChangeContent(repository: Repository) func repository(repository: Repository, didInsertRowAtIndexPath indexPath: NSIndexPath) func repository(repository: Repository, didDeleteRowAtIndexPath indexPath: NSIndexPath) func repository(repository: Repository, didUpdateRowAtIndexPath indexPath: NSIndexPath) }
  • 73. From NSFRCDelegate to RepositoryDelegate class TweetListRepository: Repository { // other delegate methods omitted for clarity func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch (type) { case .Insert: delegate?.repository(self, didInsertRowAtIndexPath: newIndexPath!) case .Delete: delegate?.repository(self, didDeleteRowAtIndexPath: indexPath!) case .Update: delegate?.repository(self, didUpdateRowAtIndexPath: indexPath!) case .Move: // consider adding separate update callback delegate?.repository(self, didDeleteRowAtIndexPath: indexPath!) delegate?.repository(self, didInsertRowAtIndexPath: newIndexPath!) } } }
  • 74. Reacting to changes extension TweetListViewController: RepositoryDelegate { // some methods omitted func repository(repository: Repository, didInsertRowAtIndexPath indexPath: NSIndexPath) { tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } func repository(repository: Repository, didDeleteRowAtIndexPath indexPath: NSIndexPath) { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } func repository(repository: Repository, didUpdateRowAtIndexPath indexPath: NSIndexPath) { tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } }
  • 76. ProfileRepository protocol SingleElementRepository { func performFetch() } protocol SingleElementRepositoryDelegate: class { func singleElementRepositoryDidUpdate(repository: SingleElementRepository) } class ProfileRepository: SingleElementRepository { weak var delegate: SingleElementRepositoryDelegate? var user: User? // computed property ... }
  • 77. !
  • 79. Issues » mutability » faulting » lack of thread safety
  • 82. protocol TweetType { var identifier: Int { get } var text: String { get } var user: UserType { get } } protocol UserType { var identifier: Int { get } var name: String { get } var profileImageUrl: String? { get } var screenName: String { get } }
  • 83. class TweetListRepository: Repository { weak var delegate: RepositoryDelegate? var objects: [TweetType] // computed property }
  • 84. Issues » mutability » faulting » lack of thread safety
  • 88. Those Structs struct Tweet: TweetType { let identifier: Int let text: String let user: User } struct User: UserType { let identifier: Int let name: String let profileImageUrl: String? let screenName: String }
  • 89. class TweetListRepository: Repository { weak var delegate: RepositoryDelegate? var objects: [TweetType] { // non-optimized version let fetchedObjects = fetchedResultsController.fetchedObjects return structsFromManagedObjects(fetchedObjects) } }
  • 90. Mutation func favoriteTweet(tweet: TweetType) { // modifies corresponding managed object under the hood }
  • 91. Issues » mutability » faulting » lack of thread safety
  • 92. New Issues » data duplication in memory » CPU time for conversions (can be in the background) » possible lack of synchronization
  • 96. Lessons learned » small classes/structs » testability » separation of concerns
  • 102. Links (1/2) » https://www.youtube.com/watch?v=WpkDN78P884 » https://www.destroyallsoftware.com/talks/boundaries » http://objectsonrails.com/ » http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean- architecture.html » https://realm.io/news/andy-matuschak-controlling- complexity/
  • 103. Links (2/2) » http://khanlou.com/2015/06/protocol-oriented-networking/ » https://twitter.com/andy_matuschak/status/ 560857237640343552 » https://github.com/rentzsch/mogenerator » https://www.objc.io/issues/13-architecture/viper/ » https://developers.facebooklive.com/videos/525/facebook- on-ios-inside-the-big-blue-app