삭제 및 파일 관리 구조
1. 시스템 요구 사항
저장 시스템에서 삭제 기능은 단순히 데이터를 지우는 기능으로 끝나지 않는다.
현재 구조는 PlayerPrefs를 기반으로 동작하며, 저장 데이터 본문과 저장 파일 목록을 별도로 관리하는 구조를 가진다.
PlayerPrefs는 키 단위 저장소이기 때문에 특정 데이터를 삭제하는 것은 DeleteKey 호출로 해결할 수 있다.
하지만 저장 시스템은 단순 키 삭제만으로 완결되지 않는다.
저장된 파일 목록은 별도의 문자열 리스트로 관리되기 때문에, 데이터를 삭제할 때는 반드시 이 목록에서도 해당 파일 이름을 제거해야 한다.
또한 UI에서는 저장 슬롯 목록을 기반으로 파일을 표시하기 때문에, 삭제 이후에도 목록이 갱신되지 않으면 존재하지 않는 파일이 화면에 남아 있는 문제가 발생한다.
따라서 삭제 시스템은 데이터 삭제와 목록 동기화가 동시에 이루어져야 한다.
여기에 더해, 특정 데이터가 존재하는지 확인하는 기능도 필요하다.
불러오기나 삭제 요청은 항상 유효한 파일을 기준으로 이루어져야 하기 때문에, 현재 저장된 데이터가 실제로 존재하는지 확인할 수 있는 검사 함수가 필요하다.
이 시스템은 PlayerPrefs에 저장된 개별 데이터와, 별도로 관리되는 파일 목록을 함께 다루면서, 삭제와 조회를 일관된 상태로 유지하는 기능을 요구한다.
2. 흐름도
2.1. 삭제
삭제 요청
↓
DeleteData(fileName)
↓
PlayerPrefs.HasKey(fileName)
↓
PlayerPrefs.DeleteKey(fileName)
↓
RemoveFileFromList(fileName)
↓
SaveFileListToPrefs(updatedList)
↓
삭제 완료
2.2. 파일 관리
파일 목록 조회
↓
GetSavedFileList()
↓
PlayerPrefs.GetString(SaveFileListKey)
↓
문자열 → List<string> 변환
↓
UI 표시
데이터 존재 여부 확인
↓
IsDataAvailable(fileName)
↓
PlayerPrefs.HasKey(fileName)
↓
true / false 반환
이 흐름에서 중요한 점은 삭제가 단일 함수 호출로 끝나지 않는다는 것이다.
PlayerPrefs에서 데이터를 제거한 뒤, 반드시 저장 파일 목록도 함께 갱신해야 한다.
이 두 단계가 분리되면 시스템 상태가 틀어지게 된다.
3. 구현
3.1. 저장 데이터 삭제
public void DeleteData(string fileName)
{
if (!PlayerPrefs.HasKey(fileName))
return;
PlayerPrefs.DeleteKey(fileName);
PlayerPrefs.Save();
RemoveFileFromList(fileName);
if (currentFileName == fileName)
currentFileName = null;
Debug.Log("Deleted file : " + fileName);
}이 함수는 저장된 데이터를 실제로 삭제하는 진입점이다.
처음에 PlayerPrefs.HasKey(fileName)을 통해 해당 데이터가 존재하는지 확인한다.
삭제 요청이 들어왔더라도 실제 데이터가 존재하지 않는 경우는 충분히 발생할 수 있기 때문에, 이 검사를 통해 불필요한 작업을 막는다.
PlayerPrefs.DeleteKey(fileName)는 해당 키를 저장소에서 삭제한다.
PlayerPrefs는 내부적으로 키-값 형태의 저장 구조를 가지기 때문에, 삭제 역시 키 단위로 수행된다.
이 호출 이후 메모리 상에서는 해당 데이터가 제거된다.
그 다음 PlayerPrefs.Save()를 호출한다.
이 함수는 현재 메모리에 반영된 변경 내용을 실제 저장소에 기록한다.
DeleteKey만 호출한 상태에서는 런타임에서는 삭제된 것처럼 보이지만, 저장소 반영 시점이 지연될 수 있다.
따라서, Save를 호출하여 삭제 상태를 즉시 확정한다.
이후 RemoveFileFromList(fileName)를 호출한다.
여기서 중요한 점은 데이터 본문과 파일 목록이 별도로 관리된다는 것이다.
PlayerPrefs에서 DeleteKey를 통해 데이터를 지우고, 저장 파일 목록에서도 해당 이름을 제거해야 한다.
저장 파일 목록에서 해당 이름을 제거하지 없으면 UI에서는 삭제된 파일이 계속 남아 있는 상태가 된다.
'currentFileName == fileName' 조건은 현재 활성 파일이 삭제된 경우를 처리한다.
현재 선택된 슬롯이 사라졌기 때문에, 이후 저장이나 불러오기 동작이 잘못된 기준을 참조하지 않도록 상태를 초기화한다.
3.2. 파일 목록 동기화
private void RemoveFileFromList(string fileName)
{
List<string> savedFileList = GetSavedFileList();
if (savedFileList.Contains(fileName))
{
savedFileList.Remove(fileName);
SaveFileListToPrefs(savedFileList);
}
}이 함수는 저장 파일 목록에서 특정 파일명을 제거한다.
GetSavedFileList 함수는 PlayerPrefs에 현재 저장된 파일 목록을 읽어와 리스트 형태로 반환한다.
이 목록은 PlayerPrefs 내부의 별도 키(SaveFileListKey)에 문자열 형태로 저장되어 있다.
이 시점의 리스트은 메모리 상의 복사본이며, 아직 저장소에서 반영되지 않은 상태이다.
savedFileList.Contains(fileName)은 리스트에 해당 파일명이 있는지를 검사한다.
List<T>.Contains는 내부적으로 순차 탐색을 수행하며, 리스트 길이에 비례한 시간(O(n))이 소요된다.
현재 구조에서는 저장 파일 개수가 많지 않기 때문에 이 방식이 충분히 단순하고 효율적이다.
savedFileList.Remove(fileName)은 파일명이 존재할 경우 해당 파일을 목록에서 제거한다.
이 연산은 리스트에서 해당 값을 찾아 삭제하고, 뒤에 있는 요소들을 앞으로 당기는 방식으로 동작한다.
이 상태에서는 메모리 상의 리스트만 변경된 상태다.
실제 저장소에는 아직 반영되지 않았기 때문에, SaveFileListToPrefs(savedFileList)를 호출한다.
이 호출은 수정된 리스트를 다시 문자열로 변환하여 PlayerPrefs에 저장하는 역할을 한다.
3.3. 저장 파일 목록 복원
public List<string> GetSavedFileList()
{
if (!PlayerPrefs.HasKey(SaveFileListKey))
return new List<string>();
string savedFiles = PlayerPrefs.GetString(SaveFileListKey);
if (string.IsNullOrEmpty(savedFiles))
return new List<string>();
return new List<string>(savedFiles.Split(','));
}이 함수는 PlayerPrefs에 저장된 파일 목록을 리스트 형태로 복원한다.
PlayerPrefs.HasKey(SaveFileListKey)는 파일 목록 자체가 존재하는지를 확인한다.
처음 실행 시에는 목록이 없을 수 있기 때문에, 이 경우 빈 리스트를 반환한다.
이 상황은 오류가 아니라 저장된 데이터가 없는 상태로 처리한다.
PlayerPrefs.GetString(SaveFileListKey)는 저장된 파일 목록 문자열을 읽어온다.
이 문자열은 "Save1, Save2, Save3" 처럼 쉼표로 구분된 형태로 저장되어 있다.
string.IsNullOrEmpty(savedFiles)는 문자열이 비어 있는 경우를 처리한다.
빈 문자열 상태에서 Split을 수행하면 불필요한 빈 항목이 생길 수 있기 때문에, 미리 처리하는 것이 안전하다.
savedFiles.Split(',')는 문자열을 쉼표 기준으로 나누어 배열을 생성한다.
Split은 문자열을 지정한 구분자로 나누는 C# 기본 함수이며, 결과는 string 배열로 반환된다.
마지막으로 new List<string>(...)를 통해 배열을 리스트로 변환한다.
배열 대신 리스트를 사용하여, 이후 Add, Remove 같은 수정 연산을 수행하기 위한 것이다.
3.4. 데이터 존재 여부 확인
public bool IsDataAvailable(string fileName)
{
return PlayerPrefs.HasKey(fileName);
}이 함수는 내부적으로 PlayerPrefs 저장소에 지정한 키가 있는지만 확인한다.
저장된 문자열 내용까지 읽지 않기 때문에 비용이 낮고, 삭제나 불러오기 전에 선행 검사를 수행하는 용도로 적합하다.
4. 개발 의도
PlayerPrefs는 저장된 키 목록을 직접 제공하지 않기 때문에, 파일 목록을 별도로 관리하는 구조가 필요했다.
PlayerPrefs는 저장된 키 목록을 제공하지 않기 때문에, 파일 목록을 별도로 관리하는 구조를 추가했다.
이로 인해 삭제 기능은 데이터 삭제와 목록 갱신을 동시에 수행해야 한다.
DeleteData는 전체 삭제 흐름을 담당하고, RemoveFileFromList는 목록 수정만 담당한다.
이렇게 나누면 각 함수가 담당하는 역할이 명확해진다.
GetSavedFileList는 문자열 기반 저장 구조를 리스트로 변환하는 역할을 담당한다.
저장 단계에서는 리스트를 문자열로 변환하고, 불러올 때 다시 리스트로 복원한다.
PlayerPrefs가 리스트를 직접 다루지 못하기 때문에, 문자열로 변환해서 저장하는 구조를 사용했다.
IsDataAvailable는 시스템 전체에서 공통적으로 사용할 수 있는 검증 함수다.
삭제나 불러오기 전에 데이터를 확인하는 기준으로 사용되며, 잘못된 입력으로 인한 오류를 줄이는 역할을 한다.
