[examples/api] Add an example fetching items from the API and saving them into Realm

This commit is contained in:
Pedro Piñera Buendía 2016-09-28 18:23:48 +02:00
parent f059a68b10
commit a1b664776e
6 changed files with 221 additions and 9 deletions

View File

@ -23,15 +23,15 @@ PODS:
- Realm (= 1.1.0)
- Result (3.0.0)
- SnapKit (3.0.1)
- SugarRecord (3.0.0-alpha.1):
- SugarRecord/CoreData (= 3.0.0-alpha.1)
- SugarRecord/CoreData+iCloud (= 3.0.0-alpha.1)
- SugarRecord/Realm (= 3.0.0-alpha.1)
- SugarRecord/CoreData (3.0.0-alpha.1):
- SugarRecord (3.0.0-alpha.2):
- SugarRecord/CoreData (= 3.0.0-alpha.2)
- SugarRecord/CoreData+iCloud (= 3.0.0-alpha.2)
- SugarRecord/Realm (= 3.0.0-alpha.2)
- SugarRecord/CoreData (3.0.0-alpha.2):
- Result (~> 3.0)
- SugarRecord/CoreData+iCloud (3.0.0-alpha.1):
- SugarRecord/CoreData+iCloud (3.0.0-alpha.2):
- Result (~> 3.0)
- SugarRecord/Realm (3.0.0-alpha.1):
- SugarRecord/Realm (3.0.0-alpha.2):
- RealmSwift (~> 1.1)
- Result (~> 3.0)
@ -58,7 +58,7 @@ SPEC CHECKSUMS:
RealmSwift: 838058b2db95b12cb86bd0cf209df642c33fb60a
Result: 1b3e431f37cbcd3ad89c6aa9ab0ae55515fae3b6
SnapKit: f818b8326d45b4e1c777d0ab27b5c0a3624bfdeb
SugarRecord: 13f9d029c077dea63c7f7240dd401ac4af15a84c
SugarRecord: 5d12c70dadef8e036edc795c76e533584b7da453
PODFILE CHECKSUM: 93e4a0d6049261cca889912a17deebad59571a81

View File

@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
23226F871D9C1ECF006A6769 /* NewsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23226F861D9C1ECF006A6769 /* NewsService.swift */; };
23226F891D9C1F1A006A6769 /* RealmNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23226F881D9C1F1A006A6769 /* RealmNew.swift */; };
23226F8B1D9C22B1006A6769 /* NewsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23226F8A1D9C22B1006A6769 /* NewsView.swift */; };
23E13E5B1D96896300204C82 /* CoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23E13E341D96896300204C82 /* CoreData.swift */; };
23E13E5C1D96896300204C82 /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23E13E351D96896300204C82 /* Realm.swift */; };
23E13E5D1D96896300204C82 /* Track+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23E13E381D96896300204C82 /* Track+CoreDataProperties.swift */; };
@ -57,6 +60,9 @@
/* Begin PBXFileReference section */
199B6E9AFF9F22F151FCACD5 /* Pods-SugarRecord_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SugarRecord_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SugarRecord_Example/Pods-SugarRecord_Example.debug.xcconfig"; sourceTree = "<group>"; };
23226F861D9C1ECF006A6769 /* NewsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsService.swift; sourceTree = "<group>"; };
23226F881D9C1F1A006A6769 /* RealmNew.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealmNew.swift; sourceTree = "<group>"; };
23226F8A1D9C22B1006A6769 /* NewsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsView.swift; sourceTree = "<group>"; };
23E13E341D96896300204C82 /* CoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreData.swift; sourceTree = "<group>"; };
23E13E351D96896300204C82 /* Realm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Realm.swift; sourceTree = "<group>"; };
23E13E381D96896300204C82 /* Track+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Track+CoreDataProperties.swift"; sourceTree = "<group>"; };
@ -125,6 +131,40 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
23226F811D9C1E9D006A6769 /* News */ = {
isa = PBXGroup;
children = (
23226F821D9C1EC6006A6769 /* Models */,
23226F841D9C1EC6006A6769 /* Services */,
23226F851D9C1EC6006A6769 /* Views */,
);
path = News;
sourceTree = "<group>";
};
23226F821D9C1EC6006A6769 /* Models */ = {
isa = PBXGroup;
children = (
23226F881D9C1F1A006A6769 /* RealmNew.swift */,
);
path = Models;
sourceTree = "<group>";
};
23226F841D9C1EC6006A6769 /* Services */ = {
isa = PBXGroup;
children = (
23226F861D9C1ECF006A6769 /* NewsService.swift */,
);
path = Services;
sourceTree = "<group>";
};
23226F851D9C1EC6006A6769 /* Views */ = {
isa = PBXGroup;
children = (
23226F8A1D9C22B1006A6769 /* NewsView.swift */,
);
path = Views;
sourceTree = "<group>";
};
23E13E331D96896300204C82 /* Helpers */ = {
isa = PBXGroup;
children = (
@ -346,6 +386,7 @@
23E13E7B1D96899000204C82 /* Examples */ = {
isa = PBXGroup;
children = (
23226F811D9C1E9D006A6769 /* News */,
23E13E7C1D96899000204C82 /* CoreData */,
23E13E831D96899000204C82 /* Realm */,
);
@ -730,10 +771,13 @@
23E13E931D96899000204C82 /* CoreDataBasicView.swift in Sources */,
23E13E941D96899000204C82 /* BasicObject.swift in Sources */,
23E13E9A1D96899000204C82 /* Random.swift in Sources */,
23226F8B1D9C22B1006A6769 /* NewsView.swift in Sources */,
23E13E921D96899000204C82 /* AppDelegate.swift in Sources */,
23E13E9B1D96899000204C82 /* ViewController.swift in Sources */,
23E13E981D96899000204C82 /* RealmBasicObject.swift in Sources */,
23226F871D9C1ECF006A6769 /* NewsService.swift in Sources */,
23E13E901D96899000204C82 /* Basic.xcdatamodeld in Sources */,
23226F891D9C1F1A006A6769 /* RealmNew.swift in Sources */,
23E13E951D96899000204C82 /* CoreDataBasicEntity.swift in Sources */,
23E13E971D96899000204C82 /* RealmBasicEntity.swift in Sources */,
23E13E961D96899000204C82 /* RealmBasicView.swift in Sources */,

View File

@ -0,0 +1,10 @@
import Foundation
import RealmSwift
class RealmNew: Object {
// MARK: - Attributes
dynamic var title: String = ""
}

View File

@ -0,0 +1,54 @@
import Foundation
import SugarRecord
import RealmSwift
class NewsService {
// MARK: - Attributes
private let session: URLSession
private let apiKey: String
private let storage: Storage
// MARK: - Init
init(session: URLSession, storage: Storage, apiKey: String) {
self.session = session
self.storage = storage
self.apiKey = apiKey
}
convenience init(storage: Storage) {
self.init(session: URLSession.shared, storage: storage, apiKey: "c7a6b4e8e221414b88a5883a98bbfbf9")
}
// MARK: - Sync
internal func sync(completion: ((Swift.Error?) -> Void)? = nil) {
let url = URL(string: "https://newsapi.org/v1/articles?source=the-next-web&sortBy=latest&apiKey=\(self.apiKey)")!
self.session.dataTask(with: url) { [weak self] (data, _, error) in
self?.save(data: data!)
completion?(error)
}.resume()
}
// MARK: - Private
private func save(data: Data) {
guard let dict = try! JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { return }
guard let articles = dict["articles"] as? [[String: Any]] else { return }
DispatchQueue.main.async {
_ = try? self.storage.operation { (context, save) -> Void in
let existing = try context.fetch(FetchRequest<RealmNew>())
try context.remove(existing)
for article in articles {
guard let title = article["title"] as? String else { return }
let new: RealmNew = try context.create()
new.title = title
}
save()
}
}
}
}

View File

@ -0,0 +1,100 @@
import Foundation
import UIKit
import SugarRecord
import RealmSwift
class NewsView: UIViewController, UITableViewDelegate, UITableViewDataSource {
// MARK: - Attributes
lazy var db: RealmDefaultStorage = {
var configuration = Realm.Configuration()
configuration.fileURL = URL(fileURLWithPath: databasePath("realm-news"))
let _storage = RealmDefaultStorage(configuration: configuration)
return _storage
}()
lazy var service: NewsService = {
return NewsService(storage: self.db)
}()
lazy var tableView: UITableView = {
let _tableView = UITableView(frame: CGRect.zero, style: UITableViewStyle.plain)
_tableView.translatesAutoresizingMaskIntoConstraints = false
_tableView.delegate = self
_tableView.dataSource = self
_tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier: "default-cell")
return _tableView
}()
var entities: [String] = [] {
didSet {
self.tableView.reloadData()
}
}
// MARK: - Init
init() {
super.init(nibName: nil, bundle: nil)
self.title = "News"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setup()
self.service.sync()
let request = FetchRequest<RealmNew>()
self.db.observable(request).observe { [weak self] (change) in
switch change {
case .initial(let values):
self?.entities = values.map({$0.title})
case .update(_, _, _):
do {
self?.entities = try self?.db.fetch(request).map({$0.title}) ?? []
} catch {}
default: break
}
}
}
// MARK: - Private
fileprivate func setup() {
setupView()
setupTableView()
}
fileprivate func setupView() {
self.view.backgroundColor = UIColor.white
}
fileprivate func setupTableView() {
self.view.addSubview(tableView)
self.tableView.snp.makeConstraints { (make) -> Void in
make.edges.equalTo(self.view)
}
}
// MARK: - UITableViewDataSource / UITableViewDelegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.entities.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "default-cell")!
cell.textLabel?.text = "\(entities[(indexPath as NSIndexPath).row])"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}

View File

@ -56,7 +56,7 @@ class ViewController: UIViewController, UITableViewDataSource, UITableViewDelega
// MARK: - UITableViewDataSource / UITableViewDelegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@ -66,6 +66,8 @@ class ViewController: UIViewController, UITableViewDataSource, UITableViewDelega
cell.textLabel?.text = "CoreData Basic"
case 1:
cell.textLabel?.text = "Realm Basic"
case 2:
cell.textLabel?.text = "News from API"
default:
cell.textLabel?.text = ""
}
@ -80,6 +82,8 @@ class ViewController: UIViewController, UITableViewDataSource, UITableViewDelega
self.navigationController?.pushViewController(CoreDataBasicView(), animated: true)
case 1:
self.navigationController?.pushViewController(RealmBasicView(), animated: true)
case 2:
self.navigationController?.pushViewController(NewsView(), animated: true)
default:
break
}