How to generalize form inputs from properties using functional reactiveSwift? - swift

When doing forms with fields i want to send if there is a change i often do
let initialOrChangedName = Signal.merge(
nameChanged.signal,
self.viewDidLoadProperty.signal
.map { _ in nil }
)
where
private let nameChangedProperty = MutableProperty<String?>(nil)
private let viewDidLoadProperty = MutableProperty(())
to get a signal that has fired once on load, so i can use it in a combineLatest when user taps a button that will fire a web request with the form value to server. Since this signal merges it will give all values that change after the initial value, allowing me to send the newest value when user taps the submit button
Usage for this is usually something like
Signal.combineLatest(intialOrChangedName, initialOrChangedAge)
.sample(on:sendButtonTappedProperty.signal)
if values sent nil, i just dont include them in the web request, but i do get the other values if some of them was changed by user.
Since this is a fairly common pattern, i want to generalize it to a single function, for example
let initialOrChangedName = nameChanged.initialOrChangedState(on: viewDidLoadProperty)
I've tried writing it
extension MutableProperty where Value: OptionalProtocol {
public func initialOrChangedState(on viewDidLoadProperty: MutableProperty<Void>) -> Signal<Value?, Error> {
return Signal.merge(self.signal.map(Optional.init),
viewDidLoadProperty.signal.map { _ in nil})
}
}
Which looks good on paper, but will return String?? for the example given, and does not work.
I've also tried writing it as a static function on Signal, but with no luck.

I guess it should be something like this:
extension MutableProperty where Value: OptionalProtocol {
public func initialOrChangedState(on viewDidLoadProperty: MutableProperty<Void>) -> Signal<Value?, Error> {
return self.signal.map({Optional<Value>($0)}).merge(with: viewDidLoadProperty.signal.map({_ in nil}))
}
}
But, whats the point of using viewDidLoadProperty? Actually, if you subscribe to your signal at the end of viewDidLoad(), you don't even need such a property and as a result you wont need that merge() thing and you wont need to extend MutableProperty protocol.
So, all you need to do is something like:
submitButton.reactive.controlEvents(.touchUpInside).observer(on: UIScheduler()).observeValues({ _ in
readInputs()
launchRequest()
})

I might be misunderstanding so forgive me, if I am. But I think something like this might help. I have this method in a library I’ve written.
public func to<T>(_ value: T) -> Signal<T, Error> {
self.map { _ in value }
}
which allows you to do something like this
let voidProperty = MutableProperty(())
let nilStringSignal: Signal<String?, Never> = voidProperty.signal.to(nil)
So then maybe your case could be something like this, which leans a bit on type inference
nameChanged.signal.merge(with: self.viewDidLoadProperty.signal.to(nil))
I know maybe that’s not quite as concise as you want. Working with generics like optionals in signals can sometimes make the type wrangling a bit frustrating 😅

Related

How can use #escaping for a func which used in didSet without using a reference type in Swift?

This down code works just fine! As soon as I update testFunc, with '#escaping', it start make error about
Escaping closure captures mutating 'self' parameter
struct TestType {
var string: String {
didSet(oldValue) {
if (oldValue != string) {
testFunc(string: string, result: { resultValue in
value = resultValue
})
}
}
}
private(set) var value: String
}
func testFunc(string: String, result: (String) -> Void) {
result(string + " updated!")
}
my goal is to be able use:
func testFunc(string: String, result: #escaping (String) -> Void) {
result(string + " updated!")
}
How can I solve the issue without using a reference type?
The problem with capturing mutating self in an #escaping closure in a struct is there are really only two choices in how Swift might theoretically attempt to do it.
The first is to capture a reference to the struct, but in many cases it lives on the stack. Since the #escaping closure could be called later, that means writing to the position on the stack where self was, but likely isn't there anymore. If that happens when the stack has shrunk, then you're writing to an address that is effectively unreachable by any other code. If it happens when the stack has grown back (or larger), then you're likely stomping on unrelated data, possibly some function's return address. If you're lucky the result will be that the program crashes. If you're unlucky, it will silently do the wrong thing.
Another possible implementation is that Swift could capture a copy, which of course, could be safely written to, but would be inaccessible to any other code. That's pretty pointless.
There is a third option Swift could do, which is it could box the struct (that is actually place it on the heap). The problem is that nothing else would know about the heap location. Again that's pretty pointless... and much much slower than allocating things on the stack.
If you really need to capture a mutating self, then you need TestType to be a class, but that means the rest of your code has to be written with reference semantics in mind.
Very likely, you need to think about whatever problem you're trying to solve in a different way. Without knowing what that is, concrete solutions are impossible to suggest.

What is the right approach for resolving save operations with Swift Combine

I have a classic situation where I want to commit some action only once. For example update some entity in database using Swift Combine. My problem is that I don't really know what is the best approach for doing something only once. How do I unsubscribe when the update is finished?
This is code snippet through the layers that I am currently using:
ViewModel:
let settingsModel: LocalSettingsModel
func saveLocalSettings(){
let cancelable = settingsUseCase
.saveLocalSettings(localSettingsModel: settingsModel)
.sink(receiveCompletion: {_ in
print("Completed!!!")
}) { _ in
print("Result of Save operation!!!")
}
}
UseCase:
func saveLocalSettings(settings: LocalSettingsModel) -> AnyPublisher<LocalSettingsModel, Error> {
return repository.saveLocalSettings(settings: settings)
}
Repository:
guard let realmSettings = LocalSettingsRealmModel(fromModel: settings) else {
return Fail<LocalSettingsModel, Error>(error: .postconditionError(errorMessage: ""))
.eraseToAnyPublisher()
}
return self.localDataSource
.saveLocalSettings(localSettings: realmSettings)
.receive(on: DispatchQueue.main)
.subscribe(on: DispatchQueue.global())
.mapError { (error) -> Error in
// do error mapping
}
.compactMap { settings in
return (LocalSettingsModel(fromModel: settings))
}
.eraseToAnyPublisher()
Data Source:
func saveLocalSettings(localSettings: LocalSettingsRealmModel) -> AnyPublisher<LocalSettingsRealmModel, LocalDataSourceError> {
do {
return Just(try saveSettings(localSettings: localSettings))
.mapError({ (Never) -> LocalDataSourceError in})
.eraseToAnyPublisher()
} catch let error as NSError {
// return some error
}
}
func saveSettings(localSettings: LocalSettingsRealmModel) throws -> LocalSettingsRealmModel
{
let realm = try Realm()
try realm.write {
realm.add(localSettings, update: .modified)
}
return localSettings
}
I would really appreciate some pointers in the direction of what is a good practice when we are not expecting continuous stream of information in reactive world like in case of functions whose purpose is to execute single action. Do I really need to use Just() like in this example or is there a way do deal with this kind of situations from subscriber side.
You want something that will convert a Publisher into a single value and then terminate, and the sequence operators in Combine are what you want to use for that kind of thing.
Combine is set up to deal with one OR many values. So you, as the consumer, need to give it some way to constrain the potentially many values into a single value, if you want to use an assign subscriber to set a value (or sink subscriber to invoke a closure where you do your save, in your case).
The sequence operators in Combine is where I'd think to look, but I can't really describe which one without knowing how many values and how you'd choose which one to apply. The two "easy" options are either first or last, but there's a variety of sequence operators that let you construct more complicated choices (including firstWhere and lastWhere which let you determine based on your own closure, which can be darned handy.
The embedded links are all to the online/free-version of Using Combine (disclosure: which I wrote) - and while I don't have any explicit examples about the sequence operators, I did flesh out the reference details for them in the book quite a bit.
Unless you're explicitly working from a publisher, you may find it easier to use a Promise library - depending on what's triggering your save. I don't know the Realm end of this to know what their API focuses on, and if you've made the publisher that's generating the data, or if that's coming from their API - and hence your desire to using Combine to solve this.

Returning value for function that throws

I've got a pretty simple question but I could only find a similar answer in C++ thread. Compiler complains on getUserFromServer function stating that it requires return value even though it can catch an exception. It is obvious WHY it asks for return value but I'm not sure how to handle the situation properly.
One way is to create some sort of dummy user and return it but it doesn't sound any good. Another way is by making return type Optional but it's just moving responsibility for nil-checks to another level, which is probably not a good idea. Any help would help.
Here's a setup to simulate behaviour I expect in real code.
enum TestError: Error {
case JustError
}
class User {}
class ServerClient {
func getUser(really: Bool) throws -> User {
var uza: User?
if really {
uza = User()
}
guard let user = uza else {
throw TestError.JustError
}
return user
}
}
func getUserFromServer() -> User {
let client = ServerClient()
let user: User
do {
user = try client.getUser(really: true)
return user
} catch TestError.JustError {
print("just an error occured")
} catch {
print("something terrible happened")
}
} //Error: missing return in a function
So imagine I'm a the caller, and I write this line of code:
let user = getUserFromServer()
print(user)
It fails somehow. Great. What do you want to happen? What should user be? What should print? (There's no right answer here; the question really is what do you want it to be?)
If you want user to be nil, then getUserFromServer should return User?. If you want user to be some default user, then you'll need a way to create that. If you want the caller to not print at all (and instead handle some error), then getUserFromServer() should throw. If you want it to crash, then you need to add a fatalError inside getUserFromServer. These are all valid, but it has to do something, and what that something is, is up to you.
That said, if the question is just advice about what it should be, looking at this code you should probably default to making it an optional unless you need some other behavior. That would be the "normal" thing here since you already "handled" the error.

How should I name a delegate method that returns a "continue" flag?

In my Swift code, I have a few methods that look like this:
protocol EditorDelegate {
// ...
func didStartSearch(query: String) -> Bool
}
class Editor: UIViewController {
func search(sender: AnyObject) {
let wasHandled = self.delegate?.didStartSearch(query) ?? false
if !wasHandled {
// do default searching behavior
}
}
}
This works, but it's not self-documenting. The didStartSearch method doesn't really communicate that it's returning a flag indicating whether the default behavior should be skipped.
What are some good options for handling this?
I tried to think of a better way to name the delegate function, below is what I came up with that makes the most sense to me. Enums are very powerful in swift, using them can make code more understandable at a glance. Also I like to think of things in terms of different states, which can be clearly defined with enums.
enum SearchStatus {
case Ready
case Processing
case Complete(result: String)
}
protocol EditorDelegate: class {
func statusForSearch(with query: String) -> SearchStatus
}
class Editor: UIViewController {
weak var delegate: EditorDelegate?
func search(sender: AnyObject) {
let query = "some input.."
guard let status = delegate?.statusForSearch(with: query) else {
// delegate not set
return
}
switch status {
case .Ready:
// actually do your search
break
case .Processing:
// search in progress
break
case .Complete(let result):
// do something with result
print("result = \(result)")
break
}
}
}
Think about the relationship between the delegating object and the object being delegated to, and the "message" (in high-level semantics, not just code) that a call to the delegate method is about. That is, does a delegate method call mean, "hey, in case you're interested, this thing happened," or, "this thing happened, what should I do about it?". If the delegate returns a value to the delegating object, you're probably in the second category.
Per Coding Guidelines for Cocoa, delegate methods should:
Start by identifying the delegating object (e.g. the tableView in tableView:didSelectRow: or the window in windowWillClose:). This is important because delegation can be a many-to-one relationship — if you have a delegate property (or setDelegate method) on one class, there's nothing preventing one object from being the delegate of many others, and indeed that can be a useful pattern for whoever adopts your delegate protocol.
If the method asks something of the delegate, either name the thing being asked (e.g. cellForRowAtIndexPath), or for Boolean conditions, describe the consequence of a positive value — this usually involves language like "should" (e.g. windowShouldClose, tableView:shouldSelectRowAtIndexPath:).
In your case, it's not entirely clear what "should" happen as a result of the delegate returning true or false, but here's a guess:
protocol EditorDelegate {
func editor(_ editor: Editor, shouldShowDefaultResultsForSearch query: String) -> Bool
}
The use of return flags is often considered problematic for many reasons. See this link for one of many explanations of the arguments for and against. Nevertheless, one solution that might help in this case would be to use a typealias.
typealias useDefaultBehaviour = Bool
protocol EditorDelegate {
func didStartSearch(query: String) -> useDefaultBehaviour
}

Swift: How to access value of "_" parameter?

I noticed that this is a valid function in Swift:
func test(_:String) {
print("How do I access '_'?")
}
How do I access the parameter?
EDIT
Additional question, is there a valid/good use-case for this?
How do I access the param?
You don't. Using that syntax you are explicitly saying you don't want to access the param.
Use case
Lets say you have access to a very powerful async API like the following.
func theAnswerToLife(success:(answer: String) -> (), failure:(error: NSError) -> ())
yes, of course I am keeping the implementation secret
Now if the function theAnswerToLife does find the answer it calls the success closure, otherwise failure is invoked.
You are forced to pass both closure/functions but you are really interested only in the answer, if something goes wrong you don't mind about the actual error.
So you could define
func tellEveryone(answer: String) {
print("The answer to life is " + answer)
}
func badNews(_:NSError) {
print("Something went wrong, we will try again tomorrow")
}
badNews can be passed as second param to theAnswerToLife and who in future will look at the code will immediately understand that badNews does not care about the received param.
theAnswerToLife(tellEveryone, failure: badNews)
This is so called wildcard matching pattern, and it is introduced just for the sake of not being able to use a parameter, because you just do not care about it.
From documentation:
A wildcard pattern matches and ignores any value and consists of an underscore (_). Use a wildcard pattern when you don’t care about the values being matched against.
You have to use a proper identifier if you need to access the argument value.
Regarding updated part of your question. I do not know why would you want to do this (just a wild idea), but if you want to completely hide argument names of a method of a public class but still be able to use them in private sub-class, you can do something like:
public class Foo {
func test(_: String, _: Int) {
print("[Ignored]")
}
}
private class Bar: Foo {
override func test(stringArgument: String, _ intArgument: Int) {
print("\(stringArgument) \(intArgument)")
}
}
Anyone external, using your library, would use abstract Foo without knowing parameter names of test method.
The point of using _ is that you are not interested in using the parameter. An example usage is this
if let _ = someVariable as? String {
//Do stuff here if someVariable is a string
//But I'm not interested in accessing the unwrapped value, so I set the unwrapped variable name to _
}