'Cannot convert value of type 'User?' to expected argument type 'UserId?' (aka 'Optional<String>')
When creating a function to addDetail, passing the userId as the userId. It comes up with this error:
Cannot convert value of type 'User?' to expected argument type 'UserId?' (aka 'Optional')
I have tried force unwrapping the userId in the addDetail function, but that didn't work.
func sendAction(action: Action)
{
switch action
{
case .addDetail:
userService.currentUser().flatMap { userId -> AnyPublisher<Void, Error> in
return self.addDetail(userId: userId) // Error Here
}.sink { completion in
switch completion
{
case let .failure(error):
print(error.localizedDescription)
case .finished:
print("Finished")
}
} receiveValue: { _ in
print("Success")
}.store(in: &cancellables)
}
}
private func addDetail(userId: UserId?) -> AnyPublisher<Void, Error>
{
guard let vehicleType = vehicleDropDown.text,
let detailType = detailDropDown.text,
let coatingType = coatingDropDown.text else { return Fail(error: NSError()).eraseToAnyPublisher() }
let detail = Detail(vehicleType: vehicleType, detailType: detailType, coatingType: coatingType, userId: userId!)
return detailService.create(detail).eraseToAnyPublisher()
}
}
I'm really not sure why this error is coming up since it makes sense to me, I may have missed something in the rest of the code that needs more experienced eyes.
Rest of code:
import SwiftUI
import Combine
import FirebaseFirestore
typealias UserId = String
final class AddDetailViewModel: ObservableObject
{
@Published var vehicleDropDown = DetailPartViewModel(type: .vehicleType)
@Published var detailDropDown = DetailPartViewModel(type: .detailType)
@Published var coatingDropDown = DetailPartViewModel(type: .coatingType)
private let userService : UserServiceProtocol
private var cancellables : [AnyCancellable] = []
private let detailService : DetailServiceProtocol
enum Action
{
case addDetail
}
init(userService: UserServiceProtocol = UserService(), detailService: DetailServiceProtocol = DetailService())
{
self.userService = userService
self.detailService = detailService
}
func sendAction(action: Action)
{
switch action
{
case .addDetail:
userService.currentUser().flatMap { userId -> AnyPublisher<Void, Error> in
return self.addDetail(userId: userId)
}.sink { completion in
switch completion
{
case let .failure(error):
print(error.localizedDescription)
case .finished:
print("Finished")
}
} receiveValue: { _ in
print("Success")
}.store(in: &cancellables)
}
}
private func addDetail(userId: UserId?) -> AnyPublisher<Void, Error>
{
guard let vehicleType = vehicleDropDown.text,
let detailType = detailDropDown.text,
let coatingType = coatingDropDown.text else { return Fail(error: NSError()).eraseToAnyPublisher() }
let detail = Detail(vehicleType: vehicleType, detailType: detailType, coatingType: coatingType, userId: userId!)
return detailService.create(detail).eraseToAnyPublisher()
}
}
extension AddDetailViewModel
{
struct DetailPartViewModel: DropDownItemProtocol
{
var selectedOption: DropDownOptions
var options: [DropDownOptions]
var headerTitle: String
{
type.rawValue
}
var dropDownTitle: String
{
selectedOption.formatted
}
var isSelected: Bool = false
private let type : DetailPartType
init(type: DetailPartType)
{
switch type
{
case .vehicleType:
self.options = vehicleTypeOptions.allCases.map { $0.toDropDownOption }
case .detailType:
self.options = detailTypeOptions.allCases.map { $0.toDropDownOption }
case .coatingType:
self.options = coatingTypeOptions.allCases.map { $0.toDropDownOption }
}
self.type = type
self.selectedOption = options.first!
}
enum DetailPartType: String, CaseIterable
{
case vehicleType = "Type of Vehicle"
case detailType = "Type of Job"
case coatingType = "Type of Coating"
}
enum vehicleTypeOptions: String, CaseIterable, DropDownOptionProtocol
{
case Sedan
case Coupe
case Wagon
case Hatchback
case Convertible
case Suv
case Minivan
case Ute
case Supercar
var toDropDownOption: DropDownOptions
{
.init(type: .text(rawValue), formatted: rawValue.capitalized)
}
}
enum detailTypeOptions: String, CaseIterable, DropDownOptionProtocol
{
case Basic
case Full
var toDropDownOption: DropDownOptions
{
.init(type: .text(rawValue), formatted: rawValue.capitalized)
}
}
enum coatingTypeOptions: String, CaseIterable, DropDownOptionProtocol
{
case Ceramic
case Hydrophobic
case None
var toDropDownOption: DropDownOptions
{
.init(type: .text(rawValue), formatted: rawValue.capitalized)
}
}
}
}
extension AddDetailViewModel.DetailPartViewModel
{
var text: String?
{
if case let .text(text) = selectedOption.type
{
return text
}
else
{
return nil
}
}
}
protocol DropDownItemProtocol
{
var options : [DropDownOptions] { get }
var headerTitle : String { get }
var dropDownTitle : String { get }
var isSelected : Bool { get set }
var selectedOption : DropDownOptions { get set }
}
protocol DropDownOptionProtocol
{
var toDropDownOption : DropDownOptions { get }
}
struct DropDownOptions
{
enum DropDownOptionType
{
case text(String)
case number(Int)
}
let type : DropDownOptionType
let formatted : String
}
struct Detail: Codable
{
let vehicleType : String
let detailType : String
let coatingType : String
let userId : String
}
protocol DetailServiceProtocol
{
func create(_ detail: Detail) -> AnyPublisher<Void, Error>
}
final class DetailService: DetailServiceProtocol
{
private let db = Firestore.firestore()
func create(_ detail: Detail) -> AnyPublisher<Void, Error>
{
return Future<Void, Error>
{
promise in
_ = self.db.collection("details").addDocument(data: [
"\(detail.vehicleType)": "\(detail.vehicleType)",
"\(detail.detailType)": "\(detail.detailType)",
"\(detail.coatingType)": "\(detail.coatingType)"
]) { err in
if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: ")
}
}
}.eraseToAnyPublisher()
}
}
Any Help will be much appreciated!
EDIT (UserService Object):
protocol UserServiceProtocol
{
func currentUser() -> AnyPublisher<User?, Never>
}
class UserService: UserServiceProtocol, ObservableObject
{
func currentUser() -> AnyPublisher<User?, Never>
{
Just(Auth.auth().currentUser).eraseToAnyPublisher()
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|