• Как runloop указывает потоку спать?

    doublench21
    @doublench21 Куратор тега Swift
    У тебя неправильное понимание.

    По своей сути - поток выполняет свою задачу и умирает. Но это иногда плохо, ибо на создание тратятся ресурсы системы. Эту проблему можно решить несколькими способами... но один из них это RunLoop. RunLoop заставляет поток оставаться живым, даже если никакой задачи на нём не выполняется (Но это не основная его задача. Основная его задача "слушать"). RunLoop стал настолько полезной штукой, что его принудительно привязали к каждому созданному потоку разработчики Apple. По-умолчанию, RunLoop не активирован. То есть для обычных потоков вам даже и знать о нём не нужно. ДА вы даже не будете создавать потоки, ибо в 99% вы работаете с абстракциями DispatchQueue/OperationQueue.

    Итак, когда RunLoop активирован, то он заставляет поток жить всё время, пока активен он сам (Я напомню, что для RunLoop это не основная цель). RunLoop способен принимать какие-либо события, но это не тема этого разговора. Так вот... когда RunLoop видит, что на "поле тишина", он переходит в спящий режим.

    А спящий режим у RunLoop это просто вечный цикл. Не верите? Смотрите:
    #define	CFRUNLOOP_SLEEP() do { } while (0)
    #define	CFRUNLOOP_SLEEP_ENABLED() (0)
    Ответ написан
    8 комментариев
  • Какой размер layout margins?

    doublench21
    @doublench21
    По умолчанию - 16
    Ответ написан
    Комментировать
  • Как визуализировать граф на Swift?

    doublench21
    @doublench21 Куратор тега Swift
    Я смотрел ваш вопрос. Проблема в том, что я не знаю алгоритма, по которому можно красиво разместить все вершины исходя из матрицы смежности. Если такой есть, скиньте. Сама рисовка трудов не составит.
    Ответ написан
  • Как спарить сложные данные JSON?

    doublench21
    @doublench21 Куратор тега Swift
    У вас JSON кривой по ссылке. В этой строчке
    {"id":67,"iconImage":"image\/catalog\/style\/modile\/icons-03.png"
    id имеет целочисленный тип, хотя во всех остальных местах это строка.
    5dd182bfe2d36713711596.jpeg

    Если не учитывать этот косяк в JSON, то такое можно спарсить как-то так:
    5dd181e2cd959773181456.png

    Код
    struct EntryList: Decodable {
      struct DynamicCodingKey: CodingKey {
        var stringValue: String
        init?(stringValue: String) { self.stringValue = stringValue }
        var intValue: Int? { nil }
        init?(intValue: Int) { nil }
      }
    
      struct Entry: Decodable {
        struct Content: Decodable {
          struct Subcategory: Decodable {
            let id: String
            let iconImage: String
            let name: String
            let sortOrder: String
            let type: String
          }
          
          let iconImage: String
          let iconImageActive: String
          let image: String
          let name: String
          let sortOrder: String
          let subcategories: [Subcategory]
        }
        
        let name: String
        let content: Content
      }
     
      let entries: [Entry]
      
      init(from decoder: Decoder) throws {
        let entriesContainer = try decoder.container(keyedBy: DynamicCodingKey.self)
        
        entries = try entriesContainer.allKeys.map { key in
          print(key)
          let content = try entriesContainer.decode(Entry.Content.self, forKey: key)
          return Entry(name: key.stringValue, content: content)
        }
      }
    }
    
    var entryList: EntryList?
    
    let task = URLSession
      .shared
      .dataTask(with: URL(string: "https://blackstarshop.ru/index.php?route=api/v1/categories")!) { (data, _, error) in
        guard error == nil else { return }
        guard let data = data else { return }
        
        entryList = try! JSONDecoder().decode(EntryList.self, from: data)
      }
    
    task.resume()
    Ответ написан
    2 комментария
  • Зачем нужен Optional и почему над null нельзя выполнить те же действия?

    doublench21
    @doublench21
    Концепция опционалов не нова и проста как банный лист. Это всего лишь перечисление(enum):
    (Полную реализацию можно глянуть тут)

    enum Optional<Wrapped>: ExpressibleByNilLiteral {
      // The compiler has special knowledge of Optional<Wrapped>, including the fact
      // that it is an `enum` with cases named `none` and `some`.
      /// The absence of a value.
      ///
      /// In code, the absence of a value is typically written using the `nil`
      /// literal rather than the explicit `.none` enumeration case.
      case none
    
      /// The presence of a value, stored as `Wrapped`.
      case some(Wrapped)
    
      /// Creates an instance that stores the given value.
      @_transparent
      public init(_ some: Wrapped) { self = .some(some) }
    
     //...


    НО люди по своей природе не любят сложностей, даже если сама идея достаточно хорошо. Никто не хочет каждый раз писать Optional<MyClass>.some(myObj) и тому сопутствующее...

    Тут та и на сцену выходит язык Swift, где концепция Опционалов выведена в абсолют и поддерживается на уровня компилятора. А что же это даёт? Достаточно много удобств: не нужно писать полный тип, добавили соответсвующие литералы("!", "?", "nil") и в целом работа с перечислением(enum Optional) сделана в виде обычного стандартного типа, Аля Int какой-нибудь.

    ---------------------------------------

    Зачем нужен Optional и почему над null нельзя...?

    Нельзя потому-что по своей природе null указывает на указатель который никуда не указывает в данный момент. Optional же позволяет растянуть эту концепцию не только на указатели(значит на ссылочные типы), но и на самые обычные типы(типы значения).
    Ответ написан
    Комментировать
  • Как получить данные из ячеек таблицы?

    doublench21
    @doublench21 Куратор тега Swift
    Ну так заведи словарь var data = [IndexPath: String]() и UITextFieldDelegate. А в методе делегата сделай так:
    func textFieldDidEndEditing(_ textField: UITextField){
        let pointInTable = textField.convert(textField.bounds.origin, to: tableView)
        guard let textFieldIndexPath = tableView.indexPathForRow(at: pointInTable) else { return }
        guard let text = textField.text else { return }
        data[textFieldIndexPath] = data[textFieldIndexPath, default: ""] + text
    }
    Ответ написан
    Комментировать
  • Как отслеживать изменения в массиве, с разделением на вставку / удаление и модификацию?

    doublench21
    @doublench21 Куратор тега Swift
    5dbd5546661d4815276402.png

    Code
    ["John", "Alpha", "Toster"]
      .difference(from: ["John", "Omega", "Alpha", "Toster"])
      .forEach { print($0) }
    
    // remove(offset: 1, element: "Omega", associatedWith: nil)
    Ответ написан
  • Как обновить интерфейс при нажатии кнопки(проблема с потоками)?

    doublench21
    @doublench21 Куратор тега Swift
    Остановку индикатора нужно делать по завершению работы. Работа с URLSession является асинхронной, поэтому останавливать индикатор нужно в completion таска, который вы запускаете.

    Все примеры показанные вами можно просто выкинуть. Это полнейший ужас.

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

    Если вы хотите показать пользователю, что идет загрузка, то сделайте оверлай, который будет показываться во время работы таска и скроется по его окончанию. Примеров миллион. Первый из гугла:
    https://stackoverflow.com/questions/27960556/loadi...

    UPD:
    5dbaf3a561387056015331.png

    Текстом
    class ViewController: UIViewController {
      
      @IBOutlet var button: UIButton!
      
      
      var alert: UIAlertController?
      
      func displayActivityIndicatorAlert() {
        alert = UIAlertController(title: "Deleting from black list...", message: nil, preferredStyle: .alert)
        let activityIndicator = UIActivityIndicatorView(style: .medium)
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        activityIndicator.isUserInteractionEnabled = false
        activityIndicator.startAnimating()
        
        alert!.view.addSubview(activityIndicator)
        alert!.view.heightAnchor.constraint(equalToConstant: 95).isActive = true
        
        activityIndicator.centerXAnchor.constraint(equalTo: alert!.view.centerXAnchor, constant: 0).isActive = true
        activityIndicator.bottomAnchor.constraint(equalTo: alert!.view.bottomAnchor, constant: -20).isActive = true
        
        present(alert!, animated: true)
      }
      
      func dismissActivityIndicatorAlert() {
        alert?.dismiss(animated: true)
        alert = nil
      }
      
      var blackList = [Int](0...9)
      let lock = NSLock()
      
      func asyncDeleteBlackList() {
        var tasks = [URLSessionTask]()
        tasks.reserveCapacity(10)
        
        var results = [Int: String]()
        results.reserveCapacity(10)
        
        let group = DispatchGroup()
        
        displayActivityIndicatorAlert()
        
        for item in blackList {
          group.enter()
          
          let url = URL(string: "https://.../api/v1/today/batch")!
          let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let error = error {
              // Что-то делаем с ошибкой на клиенте...
              return
            }
            
            guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else
            {
              // Что-то делаем с ошибкой на сервере...
              return
            }
            
            if let mimeType = httpResponse.mimeType,
              mimeType == "application/json",
              let data = data,
              let string = String(data: data, encoding: .utf8)
            {
              print("Запрос №\(item) завершён.")
              self.lock.lock()
              results[item] = string
              self.lock.unlock()
              group.leave()
            }
          }
          
          tasks.append(task)
          task.resume()
        }
        
        group.notify(queue: .main) {
          print("\nЗадача завершена.")
          self.dismissActivityIndicatorAlert()
        }
      }
      
      override func viewDidLoad() {
        button.addTarget(self, action: #selector(pressed(sender:)), for: .touchUpInside)
      }
      
      @objc
      func pressed(sender: UIButton) {
        asyncDeleteBlackList()
      }
    }


    Результат: (Видео)
    https://disk.yandex.ru/i/S5yG9YQsRRJSZg
    Ответ написан
  • Как сохранить уведомления (удалённые сообщения мессенджеров) в iOS?

    doublench21
    @doublench21
    Да никак. Приложения не имеет доступа к уведомлениям других приложений.
    Ответ написан
    Комментировать
  • Как то можно опубликовать видео на сайте чтобы было не скачиваемым?

    doublench21
    @doublench21
    DRM, но запись с экрана всё портит конечно.
    Ответ написан
    Комментировать
  • Как сделать картинку не скачиваемой?

    doublench21
    @doublench21
    Если картинку скачивает браузер, значит её может скачать кто угодно. То есть - НИКАК!
    Ответ написан
    2 комментария
  • Как устранить ошибку Challenge required. в mgp25/instagram-api?

    doublench21
    @doublench21
    Включите двух-факторку. При следующей такой попытке он отправит код с подтверждением. Эта либа попросит его ввести. После можно будет отключить двух-факторку.
    Ответ написан
    Комментировать
  • Почему пустая программа на C занимает 6 килобайт?

    doublench21
    @doublench21
    А про библиотеки ты видимо забыл(C runtime)?

    Почитать на досуге:
    https://stackoverflow.com/questions/1315926/gcc-em...
    www.muppetlabs.com/~breadbox/software/tiny/teensy.html
    Ответ написан
    Комментировать
  • Как обьеденить два словаря?

    doublench21
    @doublench21 Куратор тега Swift
    5db18233eab0c251752676.png

    Текстом
    let table1 = ["box": 3, "lamp": 1, "pen": 2]
    let table2 = ["box": 2, "PC": 1, "pen": 3]
    
    let table = table1.merging(table2) { $0 + $1 }
    
    // ["pen": 5, "lamp": 1, "PC": 1, "box": 5]
    Ответ написан
    Комментировать
  • Как отцентрировать текстовое поле в Xcode?

    doublench21
    @doublench21
    Ну так а где у вас ограничение на ширину? На скриншоте я вижу только два.

    top = safeArea.top + 351
    centerX = safeArea.centerX
    width = 300
    Ответ написан
  • Как отсортировать в словаре массивы по значению ключа?

    doublench21
    @doublench21 Куратор тега Swift
    UPD: Автор сменил вопрос. Ответ не актуален.

    Домашку нужно делать самому! А ещё закрывать вопросы.

    5db064f48049e807948975.png
    Текстом
    [
      "primes": [2, 3, 5, 7, 11, 13, 15],
      "triangular": [1, 3, 6, 10, 15, 21, 28],
      "hexagonal": [1, 6, 15, 28, 45, 66, 91],
    ].sorted { $0.key < $1.key }
    
    // [
    //   (key: "hexagonal", value: [1, 6, 15, 28, 45, 66, 91])
    //   (key: "primes", value: [2, 3, 5, 7, 11, 13, 15]),
    //   (key: "triangular", value: [1, 3, 6, 10, 15, 21, 28]),
    // ]
    Ответ написан
    6 комментариев
  • Какую ссылку прислать в письме на почту чтоб открыть установленное приложение в телефоне Android и iOS?

    doublench21
    @doublench21
    Смотря какие?

    ----------------------

    Есть такие ссылки: https://developer.apple.com/library/archive/docume...
    Они позволяют, переходя на сайт, скажем YouTube.com, перебрасывать сразу в приложение. Для этого типа нужно быть собственно владельцем и сайта и приложения.

    ----------------------

    Есть специфичные ссылки для приложения. У каждого ссылки свои. Вот пример того, что есть у Instagram
    • instagram://app The Instagram app
    • instagram://camera The camera (or photo library on non-camera devices)
    • instagram://media?id=MEDIA_ID Media with this ID App
    • instagram://user?username=USERNAME User with this username
    • instagram://location?id=LOCATION_ID Location feed for this location ID
    • instagram://tag?name=TAG Tag feed for this tag


    ----------------------

    А есть кнопки с переходом в Appstore: https://linkmaker.itunes.apple.com/en-us
    appstore-lrg-25178aeef6eb6b83b96f5f2d004
    Ответ написан
  • Как найти самый повторяемый символ в строке?

    doublench21
    @doublench21 Куратор тега Swift
    5daf297d86524526184825.png

    Текстом
    "adflksdlfdfddddflsdkflsdkflsdfZ"
      .lazy
      .reduce(into: [Character:Int]()) { $0[$1] = $0[$1, default: 0] + 1 }
      .sorted { $0.value < $1.value }
      .last // (key: "d", value: 10)


    З.Ы. Работает крайне быстро.
    Ответ написан
    Комментировать
  • Как сверстать такой блок?

    doublench21
    @doublench21
    Вот тут та верстальщики и почесали репу. Тут не верстать, тут писать нужно. Знакомься с js, коли не знаком.
    Ответ написан