How to set a tuple in a AnyPublisher in SwiftUI - swift

good morning community,
I have a very good question that I try to implement in a project but I am something new to combine
I want to do a function to check some permissions, but I want to return an AnyPublisher with a tuple inside, could someone help me who has already done it or know how to do it?
I put my code below.
func returnedPermisionReminderAuthorizationStatus(reminderPermission:EKAuthorizationStatus,calendarPermission:EKAuthorizationStatus) -> AnyPublisher<(EKAuthorizationStatus,EKAuthorizationStatus),Never>{
var reminderPermissionToPass:EKAuthorizationStatus = .notDetermined
var calendarPermissionToPass:EKAuthorizationStatus = .notDetermined
switch (reminderPermission){
case .notDetermined:
return Just(reminderPermissionToPass).eraseToAnyPublisher()
case .restricted:
reminderPermissionToPass = .restricted
return Just(reminderPermissionToPass).eraseToAnyPublisher()
case .denied:
reminderPermissionToPass = .denied
return Just(reminderPermissionToPass).eraseToAnyPublisher()
case .authorized:
reminderPermissionToPass = .authorized
return Just(reminderPermissionToPass).eraseToAnyPublisher()
#unknown default:
reminderPermissionToPass = .notDetermined
return Just(reminderPermissionToPass).eraseToAnyPublisher()
}
}
Is it possible to send a tuple in a just?

You can send a tuple from Just like this:
func returnedPermisionReminderAuthorizationStatus(
reminderPermission: EKAuthorizationStatus,
calendarPermission: EKAuthorizationStatus
) -> AnyPublisher<(EKAuthorizationStatus,EKAuthorizationStatus),Never>{
Just((reminderPermission,calendarPermission))
.eraseToAnyPublisher()
}

What about a PassthroughSubject ? If yes then try the following code :
let someResponse = PassthroughSubject<(Bool,String), Never>()
and then to receive
.onReceive(someResponse, perform: { (boolValue,StringValue) in
})

Related

Can't set AsyncStream `onTermination` handler

Has anyone succeeded in creating an AsyncStream and setting its onTermination handler? I can't do it. The following is copied and pasted directly from the proposal (https://github.com/apple/swift-evolution/blob/main/proposals/0314-async-stream.md), except I got rid of the warnings by modernizing detach into Task.detached:
let t = Task.detached {
func make123Stream() -> AsyncStream<Int> {
AsyncStream { continuation in
continuation.onTermination = { termination in
switch termination {
case .finished:
print("Regular finish")
case .cancelled:
print("Cancellation")
}
}
Task.detached {
for n in 1...3 {
continuation.yield(n)
sleep(2)
}
continuation.finish()
}
}
}
for await n in make123Stream() {
print("for-in: \(n)")
}
print("After")
}
sleep(3)
t.cancel()
Looks great, but it doesn't compile, and I can't find a way to make it compile. The error message on the onTermination setter reads:
Converting non-concurrent function value to
'#Sendable (AsyncStream<Int>.Continuation.Termination) -> Void'
may introduce data races
I don't know what the compiler is asking me to do. Has anyone worked this out, and what's the solution?
(I've filed a bug on this.)
Update:
You can work around this bug by adding #Sendable as the first thing inside the closure (before the capture list, parameters, and the in keyword), like:
continuation.onTermination = { #Sendable termination in
switch termination {
case .finished:
print("Regular finish")
case .cancelled:
print("Cancellation")
#unknown default:
break
}
}
Original answer:
Yeah I'm guessing it's a bug, because I was able to get it to compile by adding:
as (#Sendable (AsyncStream<Int>.Continuation.Termination) -> Void)
after the closure, like:
continuation.onTermination = { termination in
switch termination {
case .finished:
print("Regular finish")
case .cancelled:
print("Cancellation")
#unknown default:
break
}
} as (#Sendable (AsyncStream<Int>.Continuation.Termination) -> Void)
(I also added the #unknown default case to silence a new warning that appeared.)

What to put in switch cases that have nothing to do?

I started using Result as a return type and I mostly like it but when I have nothing to return for success then I am at a loss about what to do in that case statement. Any hints?
All that I could think of was let _ = 0
func createAppDirectory(_ searchPath: FileManager.SearchPathDirectory) -> Result<Void,Error>
...
switch createAppDirectory(searchPath) {
case .success(_): let _ = 0
case .failure(let error): return .failure(error)
}
I am beginning to think that maybe Result isn't a good fit when the success type is Void.
BTW createAppDirectory just creates Library/Application Support/<Bundle ID>. There is no value to return if it succeeds.
Use a break statement:
switch createAppDirectory(searchPath) {
case .success:
break
case .failure(let error): return .failure(error)
}
EDIT:
As Mojtaba pointed out, if you're not going to use the associated value for a particular case of your enum you can simply skip it. I've edited my answer above to remove the (_) from the .success case
Just ignore it:
case .success: break
Also if you want absolutely no overwork when it isn't failure case, gaurd it at the very beginning of the scope:
guard case .failure(let error) = createAppDirectory(searchPath) else { return <#Value#> }
If only the error is significant Result is inappropriate.
A better pattern is to throw the error and return nothing
func createAppDirectory(_ searchPath: FileManager.SearchPathDirectory) throws
...
do {
try createAppDirectory(searchPath)
} catch { print(error)}
Return simple void result,
switch createAppDirectory(searchPath) {
case .success: return .success(())
case .failure(let error): return .failure(error)
}

Set value of array via KeyPath

I am trying to update the value stored in an array property of a class via the use of KeyPaths. Here is my code:
func listenAndUpdateDocuments<T: JSONDecodable>(
_ property: ReferenceWritableKeyPath<MyModel, [T]?>,
from model: MyModel) {
guard let reference = reference else {
return
}
guard listener == nil else {
return
}
listener = backendClient.listenToDocuments(reference) { [weak model] (result: Result<[T], RequestError>) in
switch result {
case .success(let value):
model?[keyPath: property] = value
case .failure:
model?[keyPath: property] = []
}
}
}
The problem is when I call this function like this:
myListener.listenAndUpdateDocuments(\.viewers, from: self)
where viewers is of type [ViewersModel], it always comes back with the following error:
Type of expression is ambiguous without more context
How do I solve this? I have a similar version of the code but where the property parameter isn't an array, and that works.
I struggled with something similar:
_ = Token.query(on: req).filter(\.expiry < Date()).delete()
The solution I found was to use a more up-to-date api to handle my request parameters.
_ = Token.query(on: req).filter(\.expiry, .lessThan, Date()).delete()
It had less to do with the keypath itself than I thought!

RealmSwift SyncSubscription Token

How do you add listener to your SyncSubscriptions? The code from the documentation doesn’t seem to work:
let results = realm.objects(Person.self).filter("age > 18")
let subscription = results.subscribe()
let subscriptionToken = subscription.observe(\.state) { state in
switch state {
case .creating:
print("creating")
case .pending:
print("pending")
case .complete:
print("complete")
case .invalidated:
print("invalidated")
case .error(let err):
print("err")
}
This code does not execute any of those cases. Am i missing something? TIA

How to get notification authorization status in swift 3?

How can I check UNUserNotificationCenter for current authorization status in iOS 11? I've been looking for a while and found some code but it's not in swift 3 and some of functions were deprecated in iOS 10. Can anyone help?
Okay I found it:
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { (settings) in
if(settings.authorizationStatus == .authorized)
{
print("Push authorized")
}
else
{
print("Push not authorized")
}
}
code by: Kuba
When getting the notification authorization status, there are actually three states it can be in, i.e.
authorized
denied
non-determined
A straightforward way to check these is with a switch-case where .authorized, .denied, and .nonDetermined are enums in UNAuthorizationStatus
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Checking notification status")
switch settings.authorizationStatus {
case .authorized:
print("authorized")
case .denied:
print("denied")
case .notDetermined:
print("notDetermined")
}
}
Description of UNAuthorizationStatus can be found here in Apple's docs https://developer.apple.com/documentation/usernotifications/unauthorizationstatus