iOS/오류

Cannot use mutating member on immutable value 에러

skyiOS 2023. 7. 30. 03:43
반응형

 

변수가 let 으로 선언되어  변경 할 수 없다는 오류이다.

 

struct ToDo{
    var main: String
    var sub: String
    var like: Bool
    var done: Bool
    
}

해당 Todo 는 구조체로 선언 되어있다.
함수에서 todo 의 done 값을 바꾸기 위해 toggle() 함수를 사용했는데 해당 오류가 발생하였다.

  func tapCheckButton(todo: ToDo){
        if todo.done {
            checkImageView.image = UIImage(systemName: "checkmark.square.fill")
        }else{
            checkImageView.image = UIImage(systemName: "checkmark.square")
        }
        todo.done.toggle()
}

함수의  파라미터인 todo는 함수 내부에서만 쓰이는 값으로 let 으로 선언이 되어있다.
파라미터로 들어온 todo를 새로운 변수에 넣어주면 오류가 사라진다.

func tapCheckButton(todo: ToDo){
        var todoInfo = todo
        if  todoInfo.done {
            checkImageView.image = UIImage(systemName: "checkmark.square.fill")
        }else{
            checkImageView.image = UIImage(systemName: "checkmark.square")
        }
        todoInfo.done.toggle()
    }

하지만 실행해보면 값이 바뀌지 않는걸 확인 할 수 있다.

todo.done.toggle() 결과

그 이유는 파라미터로 들어오는 Todo가 구조체이기 때문이다. 구조체는 값 타입이기 때문에  값에 의한 호출(Call by Value)를 사용한다.
위 코드를 보면 todo를 todoinfo 에 넣고 toggle() 함수를 실행해 값을 바꾸게 되는데
이 때 값이 변하는 변수는 todoInfo의 done이다. 

todoInfo의 done 값이 바뀌기 때문에 파라미터로 들어온 todo의 done값이 업데이트가 되지 않는다.

예시로 코드를 작성 해본다.
Todo 구조체를 생성해서 changeTodo에 넣고 changeTodo의 done값을 바꾼 후  두 변수의 done값을 본다.

예시


해결법 

1. inout 키워드를 이용해 todo의 참조값을 넘겨서 사용한다.

tapCheckButton(todo: &todo.list[indexPath.row])


func tapCheckButton(todo: inout ToDo){
        if todo.done {
            checkImageView.image = UIImage(systemName: "checkmark.square.fill")
        }else{
            checkImageView.image = UIImage(systemName: "checkmark.square")
        }
        todo.done.toggle()
    }
값 이 바뀐 것을 확인 할 수 있다.

inout 
in-out-Parameters(입출력 매개변수) 라고 한다. 
argument(아규먼트: 전달인자) 의 값이 parameter(파라미터: 매개변수)에 복사 되는 값에 의한 호출이 아닌
argument로 넘겨진 값의 주소를 전달 받아 함수 외부에서도 값이 변경 된다.

2. Todo를 클래스로 선언 한다.

클래스는 참조타입으로 인스턴스를 생성한 후 또다른 변수에 클래스의 인스턴스를 할당 하게 되면.
값이 아닌 클래스를 가리키는 주소값을 할당하게 되어
값을 변경하면 할당한 모든 변수에 영향을 주게 됩니다.
클래스는 참조타입이다.
예시로 코드를 작성 해본다.
Todo 클래스를 생성해서 changeClassTodo에 넣고 changeClassTodo의 done값을 바꾼 후  두 변수의 done값을 본다.
changeClassTo의 done 값만 변경 했지만 같은 인스턴스를 참조하고 있기 때문에 두 변수의 값이 바뀌게 된다.

클래스로 변경 후 적용 해 본다.
class ToDo{
    var main: String
    var sub: String
    var like: Bool
    var done: Bool
    
    init(main: String, sub: String, like: Bool, done: Bool) {
        self.main = main
        self.sub = sub
        self.like = like
        self.done = done
    }
    
}


  func tapCheckButton(todo: ToDo){
        if todo.done {
            checkImageView.image = UIImage(systemName: "checkmark.square.fill")
        }else{
            checkImageView.image = UIImage(systemName: "checkmark.square")
        }
        todo.done.toggle()
        
    }
값이 바뀐 것을 확인 할 수 있다.

 
 

반응형

 

반응형