autoreleasepool

스위프트는 꽤 정교하고 효율적인 메모리 관리를 한다고 알려져 있지만 상황에 따라서 프로그래머의 의도와 전혀 다르게 동작할 수 있습니다.

다음은 디비에서 데이터를 가져와서 사진갯수를 표시하는 코드인데 데이터의 갯수가 매우 많을 경우 앱 메모리 사용량 초과로 크래시가 발생합니다. 더 좋지 않은건 크래시 발생 로그만 봐서는 메모리 사용량 초과로 OS가 강제로 앱을 죽이는 상황을 알 수가 없습니다. 아래 루프에서 스위프트는 루프가 종료될 때까지 사진 데이터 메모리를 해제하지 않습니다. for 루프가 모두 종료된 후에 사진 데이터의 메모리를 해제합니다. (ARC 환경)

extension Entry {
    var _photoCount: Int {
        get {
            if let __photos = photos {
                do {
                    let ps = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(__photos) as? [[String:Any?]]
                    let count = ps?.count ?? 0
                    return count
                } catch {
                }
            }
            return 0
        }
    }
}


var photoCount = 0
if let entrys = Fetch.entry([:]) {
    for e in entry {
        photoCount += e._photoCount
    }
}

프로그래머가 원하는 바는 for 루프가 종료될 때 일괄적인 메모리 해제가 아닌 사진의 갯수를 읽은 후 데이터의 메모리 해제를 원할 겁니다. 이 때 autoreleasepool을 사용하면 됩니다. 아래처럼 autoreleasepool 키워드를 추가하여 autoreleasepool 이 해제될 때 함께 해제됩니다.

var _photoCount: Int {
    get {
        autoreleasepool {
            if let __photos = photos {
                do {
                    let ps = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(__photos) as? [[String:Any?]]
                    let count = ps?.count ?? 0
                    return count
                } catch {
                }
            }
            return 0
        } //이 때 ps가 가리키고 있는 메모리도 함께 해제됨
    }
}

답글 남기기

이메일 주소는 공개되지 않습니다.