Home > Blockchain >  Issue with unwrapping optionals in my model and DTO
Issue with unwrapping optionals in my model and DTO

Time:08-21

This might be something really easy but I don't understand how to do it: so I have this DTO struct I use to get API data into it and map it to Model struct

my DTO:

struct PetDTO: Codable {
    var id: Int
    var category: CategoryDTO?
    var name: String?
    var photoUrls: [String]?
    var tags: [TagDTO]?
    var status: StatusDTO?
}

public class CategoryDTO: NSObject, Codable {
    var id: Int
    var name: String?
    
    private enum CodingKeys: String, CodingKey {
        case id = "id"
        case name = "name"
    }
    
    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
    }
}

public class TagDTO: NSObject, Codable {
    var id: Int
    var name: String?
    
    private enum CodingKeys: String, CodingKey {
        case id = "id"
        case name = "name"
    }
    
    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
    }
}

enum StatusDTO: String, Codable {
    case available
    case sold
    case pending
}

And my model:

struct PetDataModel {
    var id: Int
    var category: Category
    var name: String?
    var photoUrls: [String]?
    var tags: [Tags]?
    var status: Status?
    
    init(petDto: PetDTO) {
        self.id = petDto.id
        self.category = Category(categoryDto: petDto.category)
        self.name = petDto.name
        self.photoUrls = petDto.photoUrls
        for tag in petDto.tags ?? [] {
            self.tags = [Tags(tagDTO: tag)] // petDto?.map { Tags(tagDTO: $0) }
        }
        self.status = Status(rawValue: petDto.status?.rawValue)
    }
}

struct Category {
    var id: Int
    var name: String?
    
    init(categoryDto: CategoryDTO) {
        self.id = categoryDto.id
        self.name = categoryDto.name
    }
}

struct Tags {
    var id: Int
    var name: String?
    
    init(tagDTO: TagDTO) {
        self.id = tagDTO.id
        self.name = tagDTO.name
    }
}

enum Status: String, Codable {
    case available
    case sold
    case pending
}

As you can see, the mapping happens in Init of PetDataModel. I have errors on this lines

Please tell me how to fix this without making CategoryDto from PetDTO non optional, I need it to stay optional.

CodePudding user response:

You can make category form your PetDataModel optional too.

struct PetDataModel {
    var id: Int
    var category: Category?
    var name: String?
    var photoUrls: [String]?
    var tags: [Tags]?
    var status: Status?
    
    init(petDto: PetDTO) {
        self.id = petDto.id
        self.category = Category(categoryDto: petDto.category)
        self.name = petDto.name
        self.photoUrls = petDto.photoUrls
        for tag in petDto.tags ?? [] {
            self.tags = [Tags(tagDTO: tag)] // petDto?.map { Tags(tagDTO: $0) }
        }
        self.status = Status(rawValue: petDto.status?.rawValue)
    }
}

and make your initializer optional:

struct Category {
    var id: Int
    var name: String?
    
    init?(categoryDto: CategoryDTO?) {
        guard let categoryDto = categoryDto else{
            return nil
        }

        self.id = categoryDto.id
        self.name = categoryDto.name
    }
}

if you don´t want an optional initializer you can check and assign like this:

self.category = petDto.category != nil ? Category(categoryDto: petDto.category!) : nil
  • Related