SlideShare uma empresa Scribd logo
1 de 103
Baixar para ler offline
Taming
Core
Data
CocoaHeads Berlin
Arkadiusz Holko
@arekholko
holko.pl
Core Data
Anyone?
What is
Core
Data?
Core Data is a framework that you use
to manage the model layer objects in
your application.
Can
We Do
Better?
A framework that you use to build the
persistence layer in your application.
Example
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
}
9 Steps
Step #1
–
Setup
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)
}
}
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 {
}
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)
}
...
}
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
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
...
}
!
Issues
» mutability
» faulting
» lack of thread safety
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
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?
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

Mais conteúdo relacionado

Mais procurados

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 ItalyFabio Collini
 
Android architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta IndonesiaAndroid architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta IndonesiaPratama Nur Wijaya
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commandsleminhvuong
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... AgainPedro 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 scienceNiraj Bharambe
 
GKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGDG Korea
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife SpringMario Fusco
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaFabio 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 APIjagriti srivastava
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbroncymbron
 
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 SwingAdil 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 TDDMichele Capra
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authenticationWindowsPhoneRocks
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroidSavvycom Savvycom
 

Mais procurados (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
 
Android architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta IndonesiaAndroid architecture component - FbCircleDev Yogyakarta Indonesia
Android architecture component - FbCircleDev Yogyakarta Indonesia
 
Call Back
Call BackCall Back
Call Back
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
 
Java Programming - 08 java threading
Java Programming - 08 java threadingJava Programming - 08 java threading
Java Programming - 08 java threading
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... Again
 
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
 
GKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroid
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
 
AWS Java SDK @ scale
AWS Java SDK @ scaleAWS Java SDK @ scale
AWS Java SDK @ scale
 
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
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera 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.
 
12advanced Swing
12advanced Swing12advanced Swing
12advanced Swing
 
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
 
Java 7 & 8 New Features
Java 7 & 8 New FeaturesJava 7 & 8 New Features
Java 7 & 8 New Features
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
 

Semelhante a Taming Core Data with CocoaHeads Berlin

比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureAlexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureC.T.Co
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stackTomáš Kypta
 
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 FrameworkIndicThreads
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Frameworkvhazrati
 
Тарас Олексин - 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 coroutinesFabio 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 84Mahmoud 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 iOSTechWell
 
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.pdfEngmohammedAlzared
 
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 CodeIan 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 DICKonstantin Kudryashov
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaRick Warren
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive AppsJorge Ortiz
 

Semelhante a Taming Core Data with CocoaHeads Berlin (20)

比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
 
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
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
 
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
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
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
 
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
 
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)
 
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
 
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
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
 
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
 
Diifeerences In C#
Diifeerences In C#Diifeerences In C#
Diifeerences In C#
 

Último

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 

Último (20)

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 

Taming Core Data with CocoaHeads Berlin

  • 3.
  • 5.
  • 7. Core Data is a framework that you use to manage the model layer objects in your application.
  • 8.
  • 9.
  • 11.
  • 12. A framework that you use to build the persistence layer in your application.
  • 13.
  • 15.
  • 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 }
  • 27.
  • 30.
  • 31.
  • 32.
  • 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) } }
  • 39.
  • 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?
  • 49.
  • 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) } ... }
  • 54.
  • 55.
  • 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
  • 66.
  • 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. !
  • 78.
  • 79. Issues » mutability » faulting » lack of thread safety
  • 80.
  • 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
  • 85.
  • 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
  • 98.
  • 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