Ошибки джуна! Скорая помощь


#1

Предисловие, месяц назад устроился на работу, передали проект, неделю я материл все, потом смерился. Перечислю малую часть того, что меня ввело в глубочайшую депрессию.

  1. Всегда используйте в замыканиях слабую ссылочную связь https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html иначе будет ваше приложение жрать под гигабайт оперативы, а потом вылетать.

  2. Дочерний элемент в view ничего не должен знать о родительском. Опять же будет жрать гиги оперативы. Что это значит, если у Вас есть VC, то вы не должны передавать указать на него в view который находится в нем, если вам нужно на что-то отреагировать используйте notification https://www.youtube.com/watch?v=Dvhdnt12rZA

  3. Старайтесь избегать дублирование кода. пример из жизни: почти на каждом экране есть кастомная кнопка на вьюшке с тенью, все красиво, но код определяется на каждом контроллере, сделайте xib и весь дизайн определите там. Тоже самое касается cell

для меня лучшая практика

  class PointInformationCell: UITableViewCell {
    
    @IBOutlet weak var infImage: UIImageView!
    @IBOutlet weak var infName: UILabel!
    @IBOutlet weak var infDescription: UILabel!
    
    @IBOutlet weak var infNameTopConstraint: NSLayoutConstraint!
    
    static var reuseIdentifier: String {return String(describing: self)}
    static var nib: UINib {return UINib(nibName: reuseIdentifier, bundle: nil)}
    
    var model: PointInformationModel!
    
    func configure(element: PointInformationModel) {
        //инициализация ваших аутлетов
        model = element
    }
}

tableView.register(PointInformationCell.nib, forCellReuseIdentifier: PointInformationCell.reuseIdentifier)

  1. Такие элементы как cell, view, не должны хранить в себе много логики, их задача только. отображать информацию

  2. Старайтесь выносить логику, есть view, есть controller, это должны быть разные классы, один отвечает за отображение, второй, за то что отображать!

  3. Проверяйте на утечки, Leaks, деинит, и будет вам счастье, swift умный относительно памяти, но в кривых руках…

  4. Используете alamofire, вынести в отдельный слой тех же структур со статическими методами или посмотрите AlamofireRouter очень удобно.

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

  6. … и мне стало лень писать, может кто продолжет


#2

Два совета как минимум вредные:

  1. Не всегда, а только там, где нужно избегать цикла ссылок. И никак тип ссылки на потребляемую память не повлияет.
  2. iOS славится тем, что не надо тащить тонну зависимостей. Большая часть задач решаются URLSession. В некоторых проектах с требованиями к безопасности сторонний код вообще запрещён.

#3

Почему не повлияет, если объект не уничтожится?


#4

Где он не уничтожится?
Вы удерживаете ссылку на объект в замыкании ровно до тех пор, пока она Вам нужна/выполняется замыкание. Затем счетчик уменьшится и если других ссылок нет - он удалится.

Если нет - Вы где-то сделали цикл ссылок и нужно думать над weak/unowned в зависимости от задачи. Иногда вылет из-за потери unowned - даже желаемое действие.

Могу в качестве совета еще дать почитать memory manifest из swift-evolution. Там объясняются эти вещи более философски + рассказываются всякие фишки как __shared, __owned.


#5

Лучше один раз разобраться с сильными и слабыми ссылками, понять почему возникают циклы сильных ссылок и научится дебажить утечки, чем бездумно пихать weak/unowned.

В вашем PointInformationCell у аутлетов зачем слабые ссылки?


#6

Хорошо, если не сложно, объясните, когда используются слабые ссылки, а когда сильные?


#7

Вероятно когда возникает цикл сильных ссылок, нужно использовать слабые :slight_smile:

P.S. Про цикл в учебнике написано, нужно только попрактиковаться и понять как работает.


#8

Ну разумеется вы правы, и в большинстве случаев он возникает, нет?!


#9

В большинстве случаев, нет.

Если ваши случае подобны этому, то может быть.

class MyViewController {
    let mySuperGovnofire = SuperGovnofireFramework()
    
    init() {
        mySuperGovnofire.get { // [unowned self] in
            print(self)
        }
        mySuperGovnofire.call()
    }
    
    deinit {
        print("deinit: \(self)")
    }
}

class SuperGovnofireFramework {
    
    private var closure: (() -> Void)?

    func get(_ closure: @escaping () -> Void) {
        self.closure = closure
    }
    
    func call() {
        closure?()
    }
    
    deinit {
        print("deinit: \(self)")
    }
}

do {
    _ = MyViewController()
}

#10

Еще лучше кодом реализовать. И после отладки сильно не мучаться. )