Как я могу переписать переменную без изменения адреса в памяти? - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть один класс, который содержит userEnterprise

class API {

    static var sharedAPI = API()    

    var userEnterprise: Enterprise?

}

Enterprise содержит Survey, который содержит Block, как это

struct Enterprise {
   var surveys: [Survey]
}

struct Survey {
   var blocks: [Block]
}

struct Block {
   var blockStatus: BlockStatus
}

Мне нужно изменить blockStatus из другого класса, но другой класс имеет информацию только о Block, которую он должен представить

class blockPresenter(): UIViewController {
   var blockToPresent: Block

   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if surveyBlock?.subBlocks![indexPath.row].blockStatus != .answered {
            apiManager.updateBlockStatus(where: surveyBlock!.subBlocks![indexPath.row], with: surveyId!, and: .watched)
        }
    }
}

В API я пытаюсь сделать это, но это не работает

func updateBlockStatus(where searchedBlock: Block, with surveyId: Int, and newStatus: BlockStatus) {
        for survey in userEnterprise!.surveys! {
            if survey.surveyId != surveyId { continue }
            if survey.firstBlock?.subBlocks?.count == 0 { return }
            renameLater(survey.firstBlock!.subBlocks!, searchedBlock, newStatus)
        }
    }

func renameLater(_ blocks: [Block], _ searchedBlock: Block, _ newStatus: BlockStatus) {
    for var block in blocks {
        if block == searchedBlock {
            block.setBlockStatus(newStatus: newStatus)
            print("->", block.blockName, block.blockStatus)
            return
        }
        if block.subBlocks == nil { continue }
        renameLater(block.subBlocks!, searchedBlock, newStatus)
    }
    return
}

Как я могу обновить blockStatus в BlockStruct?

1 Ответ

0 голосов
/ 08 апреля 2020

У вас есть несколько способов достичь этого.

Наивным решением было бы сделать Block классом, а не структурой. Класс передается по ссылке, а не копируется. Таким образом, изменение в блоке в контроллере будет отражено в API.

Однако это не рекомендуемое решение, поскольку оно приводит к побочным эффектам и усложняет понимание вашего кода в будущем. Ваши модели должны оставаться в виде структур.

Хорошим решением было бы добавить функцию в ваш класс API:

   func update(block: Block, surveyId: String) {
       // find the survey with the Id surveyId and update its block
   }

Я полагаю, что здесь ваша структура опроса имеет некоторый идентификатор, чтобы вы могли может найти его среди других опросов предприятия.

Ваш контроллер должен понравиться

class BlockViewController: UIViewController {
   let api: API

   let surveyId: String
   var block: Block

   // ....
}

РЕДАКТИРОВАТЬ: После того, как вы обновили свой вопрос, я думаю, что я понимаю вашу проблему лучше. Когда вы пишете эту строку for var block in blocks, переменная блока является копией фактического блока, который вы хотите обновить. Так что это не обновляет ваш API.

Ниже приведен пример того, как может выглядеть API. Я взял на себя смелость использовать словари вместо массивов, так как их удобнее обновлять. Настоящий ключ здесь: enterprise.surveys[surveyId]?.update(block: block), потому что с помощью нотации [...] ( subscript ) мы получаем доступ для чтения-записи к элементам словаря.

enum BlockStatus {
    case answered
    case notAnswered
}

struct Block {

    typealias Id = Int

    let id: Id
    var status: BlockStatus
}

struct Survey {

    typealias Id = Int

    let id: Id
    var blocks: [Block.Id: Block]

    mutating func update(block: Block) {
        blocks[block.id] = block
    }
}

struct Enterprise {
    var surveys: [Survey.Id: Survey]
}

struct API {
    var enterprise: Enterprise

    mutating func update(block: Block, surveyId: Survey.Id) {
        enterprise.surveys[surveyId]?.update(block: block)
    }

    func getBlock(id: Block.Id, inSurveyWithId surveyId: Survey.Id) -> Block? {
        enterprise.surveys[surveyId]?.blocks[id]
    }
}
...