How to chan "RoomDatabase and Retrofit" in RxJava - retrofit2

I'm using the Repository Pattern.
I would like to implement logic that if there is no value in the internal DB returns the value of the Api Response and inserts it in the internal DB.
Received internal DB Value (Single Type) Return final value if found, Request Server Api if not found Insert in internal DB (Completable Type) Return final value (Single Type)
If any of these processes call onError, the final return value of this logic shall be onError.
fun getAllStudent(): Single<List<StudentEntity>> =
cache.getAllStudent().onErrorResumeNext { getAllStudentRemote() }
private fun getAllStudentRemote(): Single<List<StudentEntity>> =
remote.getAllMember()
.map { memberData -> memberData.students }
.map { studentList -> studentList.map { student -> studentMapper.mapToEntity(student) } }
.doOnSuccess { studentEntityList -> cache.insertStudents(studentEntityList) }
This is how I tried.
However, in the insert section, because it cannot subscribe, It cannot insert into internal DB or detect onError.
How can I implement this logic? ++ I'm sorry for my poor English.

Since you need to wait for cache.insertStudents() to complete, one thing you can do is to chain cache.insertStudents() into the stream using flatMap.
For example:
fun getAllStudent(): Single<List<StudentEntity>> =
cache.getAllStudent().onErrorResumeNext { getAllStudentRemote() }
private fun getAllStudentRemote(): Single<List<StudentEntity>> =
remote.getAllMember()
.map { memberData -> memberData.students }
.map { studentList -> studentList.map { student -> studentMapper.mapToEntity(student) } }
.flatMap { studentEntityList ->
cache.insertStudents(studentEntityList) // Completable
.toSingleDefualt(studentEntityList) // Convert to Single<List<StudentEntity>>
}
Also note that .do... operators are side-effect operators, and you should not do any operation that can affect the stream.

Related

Is implementing REST response in generic way general?

What I want to do is:
1. Parse model from url parameter in endpoint.(ex: media, account)
mysite.com/v1/rest/:model <- :model can be whether 'media', 'account'.
So it will look like:
mysite.com/v1/rest/media
mysite.com/v1/rest/account
2. Use 1, retrieve string and use it for getting corresponding struct.
3. Put it to the method which takes interface{}
My code looks like:
type Media struct {
Caption string
}
type Account struct {
Bio string
}
type AdminController struct {
TableName string
ID int64
}
func (c *AdminController) Get(n *core.Network) {
// I want to put struct to below GetModels method dynamically.
// Not explicitly like this.
total, data, err := c.GetModels(&Media{}, n)
// I want to do this
total, data, err := c.GetModels(caster("media"), n)
if err != nil {
n.Res.Error(err)
} else {
n.Res.Success(total, data)
}
}
Is it possible to implement method which takes string and return corresponding struct? Like this:
func (c *AdminController) caster(model string) interface{} {
if string == "media" {
return &Media{}
} else if string == "account" {
return &Account{}
}
return nil
}
If it's possible, is this a good way to deal with REST request (generic way) Or should I implement response methods one by one following table by table?
If I have to implement REST(4) * number_of_tables methods, it doesn't seem to be efficient. Any advice on this architectural problem will be appreciated.

Instance Struct variable of a mutating function in Swift

I'm having troubles using swift Structure when they have a mutating function. In this example, I have a MediaManager that fetches some data, stores them into its instance variable and calls a completion where I reload the UI.
public struct MediaManager {
//var store = MovieStore()
var movies = [String]()
mutating func fetchMovies(completion: (() -> Void) ) -> Void {
// fetch movies
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.movies = ["Ant Man", "Batman"]
print("Movies in store \(self.movies)")
print("Movies in manager \(mediaManager.allMovies())")
completion()
}
}
public func allMovies() -> [String] {
return movies
}
}
The problem is that the allMovies() is empty.
The output is
Movies in store ["Ant Man", "Batman"]
Movies in manager []
I could use a class instead of a struct but my understanding is that struct should be preferred over classes in swift. What is a proper solution for this?
cheers,
Jan
You have a closure there so every variable used by the closure must be captured, including self. However, self is a value type (struct) so capturing means copying value. When the closure is being executed, movies are set on a local copy of the struct.
Use a class (reference type). Value types are in no way preferred over reference types. Both have their uses. You have found a use case where a reference type is needed.
there are a lot of very similar questions around. your fetchMovies function returns immediately. thats all .... You add some block for later execution but at which time it will be executed?
Yes, Sultan is right, event though you need some kind of synchronization. you can play (in accordance with Sultan recommendation with reference type)
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import Foundation
public class MediaManager {
//var store = MovieStore()
var movies = [String]()
func fetchMovies(completion: (() -> Void) ) -> Void {
// fetch movies
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.movies = ["Ant Man", "Batman"]
print("Movies in store \(self.movies)")
print("Movies in manager \(self.allMovies())")
completion()
}
}
public func allMovies() -> [String] {
return movies
}
}
var mm = MediaManager()
mm.fetchMovies { print("completed") }
print("after fetch:", mm.allMovies())
with this result
after fetch: []
Movies in store ["Ant Man", "Batman"]
Movies in manager ["Ant Man", "Batman"]
completed

Compare Strings in Swift unit test

How do you test whether two Strings are equal in a Swift unit test? I've tried the == operator but it doesn't recognize it:
import XCTest
#testable import MyProject
class MyProject: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
XCTAssertNil(nil, "This test works")
}
func toJSONTest() {
let currentLocation = deviceLocation(timestamp: "2015-11-02 16:32:15 +0000",latitude: "40.2736577695212",longitude: "-111.715408331498")
var MyProjectStatuses = [MyProjectStatus(id: "", currentLocation: currentLocation)]
let json = ""
XCTAssertTrue(json == "")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock {
// Put the code you want to measure the time of here.
}
}
}
And the actual method being tested from MyProject.swift:
func toJSON ()->String{
var json = ""
json = "{\"myproject_status\":"
json = json + "{\"id\":\"" + self.Id + "\""
return json
}
This part:
XCTAssertTrue(json == "")
Throws:
Operator is not a known binary operator
The problem is that toJSONTest is not a test. Change the name to testToJSON.
This works fine on my machine:
func testToJSON() {
let json = ""
XCTAssertTrue(json == "")
}
The test runs, and passes. However, I would probably write it like this:
func testToJSON() {
let json = ""
XCTAssertEqual(json, "", "They are not equal")
}
Although this question is explicitly about how to compare two Strings in a Swift unit test, what's implicit in the question is how to compare two JSON Strings. I just wanted to point out that the right thing to do when comparing two JSON strings is to parse the JSON Strings to a Foundation object with the JSONSerialization class and then to compare the resulting Foundation objects. This approach takes care of the problem of the two JSON Strings having slightly different formatting or fields in a different order. So, for example, it's important that "{\"a\":1,\"b\":2}" and "{\"b\":2,\"a\":1}" are deemed to be equal because they are logically equal.
Here's a Swift function I put together which helps with this comparison:
class JSONAssert {
class func assertEquals(expected: String, actual: String) {
let expectedData = Data(expected.utf8)
let actualData = Data(actual.utf8)
let expectedObject: Any
let actualObject: Any
do {
expectedObject = try JSONSerialization.jsonObject(with: expectedData, options: [])
} catch {
XCTFail("Failed constructing a Foundation object from `expected` (i.e. \(expected)): \(error)")
return
}
do {
actualObject = try JSONSerialization.jsonObject(with: actualData, options: [])
} catch {
XCTFail("Failed constructing a Foundation object from `actual` (i.e. \(actual)): \(error)")
return
}
guard let expectedDictionary = expectedObject as? NSDictionary else {
XCTFail("Failed casting expected object (i.e. \(expectedObject)) to an NSDictionary")
return
}
guard let actualDictionary = actualObject as? NSDictionary else {
XCTFail("Failed casting actual object (i.e. \(actualObject)) to an NSDictionary")
return
}
XCTAssertEqual(expectedDictionary, actualDictionary)
}
}

Java 8 CompletedFuture web crawler doesn't crawl past one URL

I'm playing with the newly introduced concurrency features in Java 8, working exercises from the book "Java SE 8 for the Really Impatient" by Cay S. Horstmann. I created the following web crawler using the new CompletedFuture and jsoup. The basic idea is given a URL, it'll find first m URLs on that page and repeat the process n times. m and n are parameters, of course. Problem is the program fetches the URLs for the initial page but doesn't recurse. What am I missing?
static class WebCrawler {
CompletableFuture<Void> crawl(final String startingUrl,
final int depth, final int breadth) {
if (depth <= 0) {
return completedFuture(startingUrl, depth);
}
final CompletableFuture<Void> allDoneFuture = allOf((CompletableFuture[]) of(
startingUrl)
.map(url -> supplyAsync(getContent(url)))
.map(docFuture -> docFuture.thenApply(getURLs(breadth)))
.map(urlsFuture -> urlsFuture.thenApply(doForEach(
depth, breadth)))
.toArray(size -> new CompletableFuture[size]));
allDoneFuture.join();
return allDoneFuture;
}
private CompletableFuture<Void> completedFuture(
final String startingUrl, final int depth) {
LOGGER.info("Link: {}, depth: {}.", startingUrl, depth);
CompletableFuture<Void> future = new CompletableFuture<>();
future.complete(null);
return future;
}
private Supplier<Document> getContent(final String url) {
return () -> {
try {
return connect(url).get();
} catch (IOException e) {
throw new UncheckedIOException(
" Something went wrong trying to fetch the contents of the URL: "
+ url, e);
}
};
}
private Function<Document, Set<String>> getURLs(final int limit) {
return doc -> {
LOGGER.info("Getting URLs for document: {}.", doc.baseUri());
return doc.select("a[href]").stream()
.map(link -> link.attr("abs:href")).limit(limit)
.peek(LOGGER::info).collect(toSet());
};
}
private Function<Set<String>, Stream<CompletableFuture<Void>>> doForEach(
final int depth, final int breadth) {
return urls -> urls.stream().map(
url -> crawl(url, depth - 1, breadth));
}
}
Test case:
#Test
public void testCrawl() {
new WebCrawler().crawl(
"http://en.wikipedia.org/wiki/Java_%28programming_language%29",
2, 10);
}
The problem is in the following code:
final CompletableFuture<Void> allDoneFuture = allOf(
(CompletableFuture[]) of(startingUrl)
.map(url -> supplyAsync(getContent(url)))
.map(docFuture -> docFuture.thenApply(getURLs(breadth)))
.map(urlsFuture -> urlsFuture.thenApply(doForEach(depth, breadth)))
.toArray(size -> new CompletableFuture[size]));
For some reason you are doing all this inside a stream of one element (is that a part of the exercise?). The result is that allDoneFuture is not tracking the completion of the sub-tasks. It's tracking the completion of the Stream<CompletableFuture> that comes from doForEach. But that stream is ready right away and the futures inside of it are never asked to complete.
Fix it by removing the stream that doesn't do anything helpful:
final CompletableFuture<Void> allDoneFuture=supplyAsync(getContent(startingUrl))
.thenApply(getURLs(breadth))
.thenApply(doForEach(depth,breadth))
.thenApply(futures -> futures.toArray(CompletableFuture[]::new))
.thenCompose(CompletableFuture::allOf);

Thread safe access to a variable in a class

in an application where there could be multiple threads running, and not sure about the possibilities if these methods will be accessed under a multhreaded environment or not but to be safe, I've done a test class to demonstrate a situation.
One method has was programmed to be thread safe (please also comment if it's done right) but the rest were not.
In a situation like this, where there is only one single line of code inside remove and add, is it necessary to make them thread safe or is it going to be exaggeration.
import Foundation
class Some {}
class Test {
var dict = [String: Some]()
func has(key: String) -> Bool {
var has = false
dispatch_sync(dispatch_queue_create("has", nil), { [unowned self] in
has = self.dict[key] != nil
})
return has
}
func remove(key: String) -> Some {
var ob = dict[key]
dict[key] = nil
return ob
}
func add(key: String, ob: Some) {
dict[key] = ob
}
}
Edit after comments
class Some {}
class Test {
var dict = [String: Some]()
private let queue: dispatch_queue_t = dispatch_queue_create("has", DISPATCH_QUEUE_CONCURRENT)
func has(key: String) -> Bool {
var has = false
dispatch_sync(queue) {
has = self.dict[key] != nil
}
return has
}
func remove(key: String) -> Some? { //returns
var removed: Some?
dispatch_barrier_sync(queue) {
removed = self.dict.removeValueForKey(key)
}
return removed
}
func add(key: String, ob: Some) { //not async
dispatch_barrier_sync(queue) {
self.dict[key] = ob
}
}
}
The way you are checking whether a key exists is incorrect. You are creating a new queue every time, which means the operations are not happening synchronously.
The way I would do it is like so:
class Some {}
class Test {
var dict = [String: Some]()
private let queue: dispatch_queue_t = dispatch_queue_create("has", DISPATCH_QUEUE_CONCURRENT)
func has(key: String) -> Bool {
var has = false
dispatch_sync(queue) { [weak self] in
guard let strongSelf = self else { return }
has = strongSelf.dict[key] != nil
}
return has
}
func remove(key: String) {
dispatch_barrier_async(queue) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.dict[key] = nil
}
}
func add(key: String, ob: Some) {
dispatch_barrier_async(queue) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.dict[key] = ob
}
}
}
Firstly, I am creating a serial queue that is going to be used to access the dictionary as a property of the object, rather than creating a new one every time. The queue is private as it is only used internally.
When I want to get a value out of the class, I am just dispatching a block synchronously to the queue and waits for the block to finish before returning whether or not the queue exists. Since this is not mutating the dictionary, it is safe for multiple blocks of this sort to run on the concurrent queue.
When I want to add or remove values from the dictionary, I am adding the block to the queue but with a barrier. What this does is that it stops all other blocks on the queue while it is running. When it is finished, all the other blocks can run concurrently. I am using an async dispatch, because I don't need to wait for a return value.
Imagine you have multiple threads trying to see whether or not key values exist or adding or removing values. If you have lots of reads, then they happen concurrently, but when one of the blocks is run that will change the dictionary, all other blocks wait until this change is completed and then start running again.
In this way, you have the speed and convenience of running concurrently when getting values, and the thread safety of blocking while the dictionary is being mutated.
Edited to add
self is marked as weak in the block so that it doesn't create a reference cycle. As #MartinR mentioned in the comments; it is possible that the object is deallocated while blocks are still in the queue, If this happens then self is undefined, and you'll probably get a runtime error trying to access the dictionary, as it may also be deallocated.
By setting declaring self within the block to be weak, if the object exists, then self will not be nil, and can be conditionally unwrapped into strongSelf which points to self and also creates a strong reference, so that self will not be deallocated while the instructions in the block are carried out. When these instructions complete, strongSelf will go out of scope and release the strong reference to self.
This is sometimes known as the "strong self, weak self dance".
Edited Again : Swift 3 version
class Some {}
class Test {
var dict = [String: Some]()
private let queue = DispatchQueue(label: "has", qos: .default, attributes: .concurrent)
func has(key: String) -> Bool {
var has = false
queue.sync { [weak self] in
guard let strongSelf = self else { return }
has = strongSelf.dict[key] != nil
}
return has
}
func remove(key: String) {
queue.async(flags: .barrier) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.dict[key] = nil
}
}
func add(key: String, ob: Some) {
queue.async(flags: .barrier) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.dict[key] = ob
}
}
}
Here is another swift 3 solution which provides thread-safe access to AnyObject.
It allocates recursive pthread_mutex associated with 'object' if needed.
class LatencyManager
{
private var latencies = [String : TimeInterval]()
func set(hostName: String, latency: TimeInterval) {
synchronizedBlock(lockedObject: latencies as AnyObject) { [weak self] in
self?.latencies[hostName] = latency
}
}
/// Provides thread-safe access to given object
private func synchronizedBlock(lockedObject: AnyObject, block: () -> Void) {
objc_sync_enter(lockedObject)
block()
objc_sync_exit(lockedObject)
}
}
Then you can call for example set(hostName: "stackoverflow.com", latency: 1)
UPDATE
You can simply define a method in a swift file (not in a class):
/// Provides thread-safe access to given object
public func synchronizedAccess(to object: AnyObject, _ block: () -> Void)
{
objc_sync_enter(object)
block()
objc_sync_exit(object)
}
And use it like this:
synchronizedAccess(to: myObject) {
myObject.foo()
}

Resources