как заставить deinit действовать в swift

У меня есть класс автомобилей. Допустим, автомобиль отправляется на свалку, этот автомобиль больше не должен учитываться в общей численности населения. У меня есть функция deinit, но как систематически удалять автомобиль из популяции автомобилей? Другими словами, как заставить deinit действовать?

У меня есть переменная класса isJunk, но я не знаю, как ее использовать, чтобы это работало.

class Car {
    static var population: Int = 0
    var isJunk: Bool = false
    var color: String
    var capacity: Int
    var driver: Bool?
    var carOn: Bool = false
    init (carColor: String, carCapacity: Int) {
        self.capacity = carCapacity
        self.color = carColor
        Car.population += 1

    }
    deinit {
        Car.population -= 1
    }

    func startCar() {
        self.carOn = true
    }
}

person Govind Rai    schedule 24.06.2016    source источник
comment
Isjunk ничего не сделает. Как только объект деинициализируется, его указатель теряется, и вы больше не можете его использовать. Самый простой способ отправить объект в сборщик мусора — просто установить для каждой ссылки на этот объект значение nil. Автоматический подсчет ссылок сделает все остальное.   -  person Philip Feldmann    schedule 25.06.2016
comment
@Philip Feldmann: я думаю, что в Xcode нет сборки мусора. просто АРК   -  person Ulli H    schedule 25.06.2016
comment
Вы правы, есть только ARC, однако, когда все ссылки равны нулю, ARC избавится от объекта и будет вызван deinit. Если это не называется, у вас есть утечка.   -  person Feldur    schedule 25.06.2016
comment
@Feldur Это также относится к GC. GC — это не какая-то волшебная серебряная пуля, которая предсказывает, что вам больше не понадобится, и освобождает это у вас из-под носа. Это требует от вас избавиться от ссылок на объекты, которые вам больше не нужны. Он очистит только те объекты, на которые нет ссылки. Если вы сохраняете ссылку, но никогда ее не используете, это утечка, будь то GC, ARC или ручное управление.   -  person Alexander    schedule 12.09.2019
comment
@Александр Конечно. Это было верно еще до того, как я впервые модифицировал интерпретатор Лиспа много десятилетий назад, и это останется верным на десятилетия вперед. Технология GC сильно изменилась по сравнению с той ранней системой маркировки и развертки, но это все еще просто алгоритм.   -  person Feldur    schedule 13.09.2019


Ответы (2)


class Car {
    static var population: Int = 0
    init() {
        Car.population += 1

    }
    deinit {
        Car.population -= 1
    }
}

var cars: [Car] = [Car(), Car()]
print("Population:", Car.population) // "Population: 2"

// now the second car is removed from array and we have no other references to it
// it gets removed from memory and deinit is called
cars.removeLast()
print("Population:", Car.population) // "Population: 1"

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

Чтобы хранить элементы в памяти, вам всегда понадобится какой-то регистр (например, массив) для них. И этот регистр может вести их подсчет.

Одна возможность:

class CarPopulation {
    var liveCars: [Car] = []
    var junkCars: [Car] = []
}

Или вы можете хранить их в одном массиве и установить junk для автомобиля и при необходимости подсчитывать исправные автомобили:

class CarPopulation {
    var cars: [Car] = []

    func liveCars() -> Int {
        return self.cars.filter { !$0.junk }.count
    }
}

Есть много возможностей, но извлечение жетонов какому-то другому классу, владеющему автомобилями, вероятно, является лучшим решением.

person Sulthan    schedule 24.06.2016
comment
Я понимаю! Не могли бы вы дать некоторое представление о том, скажем, если вместо массива это были var car = Car() и var car2 = Car(). Как бы вы удалили вторую ссылку? - person Govind Rai; 25.06.2016
comment
Вы можете удалить ссылку, выполнив car2 = nil, если это единственная ссылка на объект позади car2. - person Philip Feldmann; 25.06.2016
comment
Однако обратите внимание, что deinit не обязательно вызывать немедленно. - person Sulthan; 25.06.2016
comment
@PhilipFeldmann, возможно, я неправильно понимаю ваш комментарий, но когда я устанавливаю car2 на ноль, я получаю error: nil cannot be assigned to type 'Car'. Не уверен, что вы имеете в виду, если это единственная ссылка на объект позади car2 - person Govind Rai; 25.06.2016
comment
@GovindRai В Swift вы не можете установить переменные, которые не являются необязательными, равными нулю, поэтому ваша переменная должна быть необязательной. Когда вы инициализируете объект, ОС освобождает место в вашей памяти для этого объекта. У вас может быть несколько указателей на один и тот же объект (адрес памяти), например, car3 = car2 не создаст копию car2, а только создаст новую ссылку. Вы должны удалить каждую ссылку на объект, чтобы сборщик мусора вызвал метод deinit. Однако, как уже упоминал Султан, лучше позволить другому классу обрабатывать подсчет. - person Philip Feldmann; 25.06.2016
comment
Однако обратите внимание, что deinit не обязательно вызывать немедленно. Не понимаю этот комментарий - я думал, что предполагаемое преимущество ARC по сравнению со сборкой мусора заключается в том, что он полностью детерминирован. - person RenniePet; 12.03.2017
comment
@RenniePet Это детерминировано, но в некоторых ситуациях требуется, чтобы система отложила освобождение (например, до завершения текущего метода). ARC также работает с большим количеством кода, отличного от ARC, а это означает, что пулы автоматического освобождения активно используются, откладывая освобождение до тех пор, пока данный пул не будет опустошен. Для временных объектов мы обычно можем быть уверены, что объект немедленно освобождается. Хотя детерминизм присутствует всегда. - person Sulthan; 12.03.2017
comment
Хорошо, спасибо. Но что стоит моего мнения, так это то, что сборка мусора намного лучше, чем ARC. Теперь я живу в постоянном страхе перед утечкой памяти. При работе с C# и Java я могу спать по ночам. - person RenniePet; 12.03.2017
comment
@RenniePet Разные инструменты для разных задач. Имея многолетний опыт работы с ARC, я могу сказать, что если вы поддерживаете простую и понятную иерархию объектов, риск утечек отсутствует. Большинство утечек также можно обнаружить с помощью приборов. GC требует много памяти и снижает производительность. Я провел много дней, работая над IDE, построенными на Java, и мне до сих пор снятся кошмары об увеличении размера кучи и ожидании, пока сборщик мусора выполнит свою работу. - person Sulthan; 12.03.2017
comment
@RenniePet Ничто из обсуждаемого здесь не имело риска утечки памяти ни в ARC, ни в GC. ARC пропускает память только с сильными эталонными циклами. GC в основном всегда пропускает некоторую память, краткосрочную, до следующей очистки. Я предлагаю вам проверить sealedabstract.com/rants/why-mobile- web-apps-are-slow , это увлекательное чтение. - person Alexander; 12.09.2019

deinit вызывается при освобождении экземпляра of Car (когда вы полностью избавляетесь от экземпляра объекта). Когда вы отправляете экземпляр Car на свалку, я не думаю, что вы хотите избавиться от экземпляра Car, вы просто хотите изменить его местоположение. Я бы предложил другую функцию для обработки изменения местоположения Car.

Возможно:

func changeLocation(newLocation: String) {
   // Perhaps add an instance variable to 'remember' the location of the car
   switch newLocation {
   case "junkyard":
     Car.population -= 1
   default:
      // Perhaps check whether previous location was Junkyard and increment  
      // counter if the Car is coming out of the Junkyard
      print("Unrecognized location")
   }

}
person user212514    schedule 24.06.2016