Ответы пользователя по тегу Swift
  • Как передать данные в кастомную ячейку UITableViewCell перед тем, как она будет построена?

    doublench21
    @doublench21 Куратор тега Swift
    Пример из моего проекта. (Код не привожу текстом, ужасный редактор.)

    В делегате:
    5c7bf8b3c0d26725364424.png
    internal override func collectionView(
      _ collectionView: UICollectionView,
        cellForItemAt indexPath: IndexPath
      ) -> UICollectionViewCell
      {
        let cell = collectionView.dequeueReusableCell(
          withReuseIdentifier: CategoriesCollectionViewCell.reuseIdentifier,
          for: indexPath
        ) as! CategoriesCollectionViewCell
    
        let randomIndex = indexPath.item % CategoriesPlaceholder.images.count
    
        cell.configure(
          withImage: UIImage(named: CategoriesPlaceholder.images[randomIndex])!,
          andTitle: CategoriesPlaceholder.titles[randomIndex]
        )
    
        return cell
      }

    Внутри ячейки:
    5c7bf8c1617ce913362365.png
    internal final class CategoriesCollectionViewCell: UICollectionViewCell {
    
     // =====================================
      // MARK: - Configure
      // =====================================
    
      internal func configure(withImage image: UIImage?, andTitle title: String) {
        illustrationCircle.image = image
        self.title.text = title
      }
    Ответ написан
    7 комментариев
  • Deadlcok в swift?

    doublench21
    @doublench21 Куратор тега Swift
    Это справедливо не только для главного потока, НО и для всех последовательных очередей.

    Рассмотрим вот такой пример:
    5c76b22e12b96350728646.png

    Что мы получаем:
    Очевидно, всякая последовательная очередь ждёт выполнения текущей задачи, перед тем как начать выполнять следующую. Когда мы пытаемся СИНХРОННО поставить в очередь текущую задачу, мы получаем блокировку. Это происходит потому, что когда мы выполняем код (3-я строчка), то мы это делаем в рамках текущей, уже выполняющейся в очереди задачи И пытаемся синхронно добавить задачу. Синхронно означает, что мы должны дождаться завершения текущей задачи. Но как мы можем завершить задачу в которой мы находимся, если мы сами её и тормозим? Это и называется взаимной блокировкой. 2-ая строка кода ждёт выполнения 3-ей строки, а 3-я строка ждёт завершения 2-ой. Под строками я понимаю собственно блоки кода, которые мы добавляем в ПОСЛЕДОВАТЕЛЬНУЮ очередь.

    А что до главного потока, это происходит неявно. Ведь мы по умолчанию уже находимся внутри задачи помещенной в главную очередь. И если мы попытаемся сделать так же, как и в 3-ей строке - получим блокировку.

    Об этом написано у Apple:
    Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call. Doing so will deadlock the queue. If you need to dispatch to the current queue, do so asynchronously using the dispatch_async function.


    Касаемо:
    5c76b5872101c484838312.png
    Будем идти по порядку. Начинаем с #1 - печатаем "a". После выполняем #2. Тут мы АСИНХРОННО добавляем в очередь задачу. Это значит, что мы говорим системе, эй, поставь эту задачу в очередь и верни мне контроль над кодом, я не хочу ждать. Поэтому после #2 тут же выполняется #6. Ведь мы и сказали, что не хотим ждать завершения добавленной задачи. Вот он и вернул управления и продолжил выполнять. То есть вывел символ "d".
    Теперь внутри очереди мы снова добавляем АСИНХРОННО новую задачу в рамках текущей задачи. То есть мы так же говорим, что бы система передала управление обратно и мы не хотим ждать завершения. То есть после добавления задачи мы тут же выполняем строку #5 - выводим символ "c".

    Так как добавить задачу в очередь занимает некоторое время, плюс то время, что тратится на выполнение самой задачи - всё это приводит к тому, что вывод строки #4 пришелся самым последним.

    То есть всё это время мы просили лишь добавить задачи в очередь и продолжить выполнять следующие строчки кода не дожидаясь их завершения. Вот символы "a, d, c" и вывелись раньше символа "b".

    Не знаю как ещё проще объяснить. Может кто поправит меня.
    Ответ написан
    2 комментария
  • Как отобразить snapshot в NavigationController с кастомной AnimateTransition?

    doublench21
    @doublench21 Куратор тега Swift
    Что-то мне подсказывает, что Вы совершенно не понимаете логику переходов между VC и ГЛАВНОЕ в каком контексте это происходит.

    Во-первых: Что за Магическая необходимость заставила вас удалять вью контроллера из которого вы переходите - неясно... А как вы перейдете назад? В никуда.

    Во-вторых: Предоставляете ли вы свой класс анимации, тут Важно, не Контроллеру, к которому переходите, а Навигейшн Контроллеру? Что-то мне подсказывает, нет.

    В-третьих: Вот полностью рабочий вариант. (Рабочий в том смысле, что он делает то, что вы хотите. Опущены проверки)

    5c70127785756462005262.png
    .
    Код текстом
    internal final class ModalAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    
      private var isPresenting: Bool
    
      private let duration: TimeInterval = 3
    
      internal init(isPresenting: Bool) {
        self.isPresenting = isPresenting
      }
    
      internal func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
      }
    
      internal func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromVC = transitionContext.viewController(forKey: .from),
          let toVC = transitionContext.viewController(forKey: .to),
          let snapshot = toVC.view.snapshotView(afterScreenUpdates: true)
          else { return }
    
        let containerView = transitionContext.containerView
    
        snapshot.frame = fromVC.view.frame
    
        containerView.addSubview(toVC.view)
        containerView.addSubview(snapshot)
    
        fromVC.view.isHidden = true
    
        UIView.animate(
          withDuration: duration,
          animations: { snapshot.transform = CGAffineTransform(rotationAngle: .pi)},
          completion: { _ in
            fromVC.view.isHidden = false
            snapshot.removeFromSuperview()
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        })
      }
    }
    Ответ написан
  • Как поменять UIViewController внутри модального окна?

    doublench21
    @doublench21 Куратор тега Swift
    Потому-что в нормальном варианте это должно выглядеть следующим образом:

    [MainScreenVC]
    Button1
    ---> present [LogInVC]
    ------> present [NavigationController]
    ---------> push [UserFeedVC]
    Button2
    ---> present [SignInVC]
    ------>present [NavigationController]
    --------->push [UserFeedVC]
    Ответ написан
    Комментировать
  • Как обрабатывать нажатия на SKShapeNode?

    doublench21
    @doublench21 Куратор тега Swift
    Странный вопрос. Вы вроде такие классы юзаете, а про основы совсем либо не знаете либо забыли.

    override func touchesBegan(_ touches: Set, with event: UIEvent?)

    Для определения какая это нода, смотрите св-во name у вашей ноды.
    Ответ написан
  • Почему view's перерисовывается в cell?

    doublench21
    @doublench21 Куратор тега Swift
    class CustomProgressBar: UIView {
        
        var proportion = 1.0 { 
          didSet { invalidateIntrinsicContentSize() }
        }
    
        
        override var intrinsicContentSize: CGSize {
            return CGSize(width: proportion, height: 1.0)
        }
    
    }
    Ответ написан
  • Как использовать данные модели в layoutSubviews?

    doublench21
    @doublench21 Куратор тега Swift
    А что тут думать та?

    frame.width в кастомном view в layoutSubviews

    Что это за набор слов? Зачем?

    2570 = 630 + 440 + 1500

    2570 - 100%
    630 - x
    x = (630 * 100) / 2570 ~ 24.5

    2570 - 100%
    440 - x
    x = (440 * 100) / 2570 ~ 17.1

    2570 - 100%
    1500 - x
    x = (1500 * 100) / 2570 ~ 58.3

    class StackProgressView: UIView {
    
      var proportion = 1.0
    
      override var intrinsicContentSize: CGSize {
        return CGSize(width: proportion, height: 1.0)
      }
    }
    
    let stack = UIStackView(frame: CGRect(origin: .zero, size:CGSize(width: 500.0, height: 20.0)))
        stack.distribution = .fillProportionally
        stack.axis = .horizontal
        stack.spacing = 5.0
    
    let walk = StackProgressView(frame: .zero)
        walk.backgroundColor = UIColor(red: 162.0 / 255.0, green: 221.0 / 255.0, blue: 239.0 / 255.0, alpha: 1.0)
        walk.proportion = 24.5
        walk.layer.allowsEdgeAntialiasing = true
        walk.layer.cornerRadius = 5.0
        walk.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
    
    let aerobic = StackProgressView(frame: .zero)
        aerobic.backgroundColor = UIColor(red: 69.0 / 255.0, green: 187.0 / 255.0, blue: 223.0 / 255.0, alpha: 1.0)
        aerobic.proportion = 17.1
    
    let run = StackProgressView(frame: .zero)
        run.backgroundColor = UIColor(red: 40.0 / 255.0, green: 112.0 / 255.0, blue: 133.0 / 255.0, alpha: 1.0)
        run.proportion = 58.3
        run.layer.allowsEdgeAntialiasing = true
        run.layer.cornerRadius = 5.0
        run.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
    
    stack.addArrangedSubview(walk)
    stack.addArrangedSubview(aerobic)
    stack.addArrangedSubview(run)


    yoPw0or.png
    Ответ написан
    2 комментария
  • Как решить лимит с запланированными оповещениями?

    doublench21
    @doublench21 Куратор тега Swift
    А кто Вам мешает поставить задачу в бэкграунд и запрашивать даты каждый день в 00:00 скажем и добавлять оповещение? Или скажем запрашивать новые даты с более длительным периодом. Никто же Вас не заставляет в один день устанавливать 200 оповещений. Получайте новые даты и устанавливайте их по мере необходимости. В приложение для этого заходить не нужно.

    Второй вариант использовать EventKit(Календарь, Напоминания). Там вообще лимитов нет.
    Ответ написан
    2 комментария
  • Как реализовать простое подключение NEVPNManager?

    doublench21
    @doublench21 Куратор тега Swift
    Сколько бы я не искал, пытался найти, подробной информации и примера кода нигде нет.

    Что-то крайне хреново Вы искали.

    blog.moatazthenervous.com/create-a-vpn-connection-...
    blog.moatazthenervous.com/create-a-key-chain-for-a...
    https://stackoverflow.com/questions/47351441/vpn-c...

    По этим ссылкам информации более чем достаточно, что бы сделать то, что Вы хотите. Вам осталось лишь немного раскинуть мозгами и дополнить код из 1ой ссылки, кодом из 2 и 3их ссылок.

    P.S. И денег не надо. Welcome!
    Ответ написан
  • Как в Swift в консольном приложении получить параметры его запуска?

    doublench21
    @doublench21 Куратор тега Swift
    Ну что значит как. У Вас есть Swift. У Swift есть стандартная библиотека, которую подключать конечно же не надо, она и так доступна. Очевидно она умеет делать такие базовые вещи. Та дам https://developer.apple.com/documentation/swift/co... Ну а дальше гугл вам поможет.
    Ответ написан
    1 комментарий
  • Как получить текст смс?

    doublench21
    @doublench21 Куратор тега Swift
    Читать сообщения конечно же нельзя. Но начиная с iOS 12 у Вас есть возможность получить код подтверждения для вашего приложения, присланное смской.

    if #available(iOS 12, *) {
      textField.textContentType = .oneTimeCode
    }
    Ответ написан
    2 комментария
  • Как отключить "Жирный шрифт" в приложении, который включен для всей системы?

    doublench21
    @doublench21 Куратор тега Swift
    Ну вообще говоря отключать это не нужно. Не каждый, кто пользуется вашим приложением видит так же хорошо, как и Вы. Этот ползунок сильно помогает людям с плохим зрением и это нужно учитывать.

    Что бы отключить такое поведение, достаточно отключить свойство adjustsFontForContentSizeCategory у UIFont, которое не зря по умолчанию выставлено в true.

    По умолчанию шрифт полученный методами preferredFont(forTextStyle:), preferredFont(forTextStyle:compatibleWith:) и от UIFontMetrics включает это свойство, для остальных шрифтов - отключён. Вот ваш способ и сработал.
    Ответ написан
    Комментировать
  • Как разблокировать пользователю интерфейс при скроле таблицы?

    doublench21
    @doublench21 Куратор тега Swift
    Проблема(если это вообще можно назвать проблемой) заключается в том, что UITableView не пропускает ивенты UIEvent во время скролла своим сабвьюхам. Поэтому ваш UIDatePicker и не получает никаких касаний(ивентов UIEvent), до тех пор, пока не остановить таблицу.

    Решений тут может быть несколько:
    1) Переопределять метод
    func hitTest(_ point: CGPoint,  with event: UIEvent?) -> UIView?
    у UITableView;
    2) https://stackoverflow.com/questions/16882737/scrol... ;
    Ответ написан
    Комментировать
  • Как использование базы данных SQLite в Swift 4.2?

    doublench21
    @doublench21 Куратор тега Swift
    Честно говоря, если при таком обилии различных материалов, вы не можете провести миграцию и использовать бд, то наверно лучше все же подучить Swift.

    В порядке убывания сложности:
    GRDB
    SQLite Swift
    Core Data
    Ответ написан
    1 комментарий
  • Может ли iOS очистить значения свойств класса?

    doublench21
    @doublench21 Куратор тега Swift
    Если у Вас действительно такой кэш, какой вы показали, то это ужасно.

    По делу: само по себе свойство не может очиститься. Либо система посчитает нужным и полностью выбросит ваше приложение из памяти, либо вы вернётесь, как ни в чем не бывало.
    Ответ написан
    3 комментария
  • Как из NSSet преобразовать в другой тип?

    doublench21
    @doublench21 Куратор тега Swift
    5b8d4b617ba06911513554.png
    У меня тут для NSSet, если у Вас там NSSet?, то Вы знаете что делать.
    Ответ написан
    1 комментарий
  • Как работают вложенные функции?

    doublench21
    @doublench21 Куратор тега Swift
    Доброго времени суток. Вопрос немного странный.

    Вопрос 1
    Достаточно зайти вот сюда и обнаружить, что метод auth всего лишь возвращает инстанц класса FIRAuth Собственно все ваши currentUser тут присутствуют. Думаю теперь вопросов быть не должно.
    spoiler
    @implementation FIRAuth {
      /** @var _currentUser
          @brief The current user.
       */
      FIRUser *_currentUser;
    
      /** @var _firebaseAppName
          @brief The Firebase app name.
       */
      NSString *_firebaseAppName;
    
      /** @var _listenerHandles
          @brief Handles returned from @c NSNotificationCenter for blocks which are "auth state did
              change" notification listeners.
          @remarks Mutations should occur within a @syncronized(self) context.
       */
      NSMutableArray<FIRAuthStateDidChangeListenerHandle> *_listenerHandles;
    
      /** @var _keychain
          @brief The keychain service.
       */
      FIRAuthKeychain *_keychain;
    
      /** @var _lastNotifiedUserToken
          @brief The user access (ID) token used last time for posting auth state changed notification.
       */
      NSString *_lastNotifiedUserToken;
    
      /** @var _autoRefreshTokens
          @brief This flag denotes whether or not tokens should be automatically refreshed.
          @remarks Will only be set to @YES if the another Firebase service is included (additionally to
            Firebase Auth).
       */
      BOOL _autoRefreshTokens;
    
      /** @var _autoRefreshScheduled
          @brief Whether or not token auto-refresh is currently scheduled.
       */
      BOOL _autoRefreshScheduled;
    
      /** @var _isAppInBackground
          @brief A flag that is set to YES if the app is put in the background and no when the app is
              returned to the foreground.
       */
      BOOL _isAppInBackground;
    
      /** @var _applicationDidBecomeActiveObserver
          @brief An opaque object to act as the observer for UIApplicationDidBecomeActiveNotification.
       */
      id<NSObject> _applicationDidBecomeActiveObserver;
    
      /** @var _applicationDidBecomeActiveObserver
          @brief An opaque object to act as the observer for
              UIApplicationDidEnterBackgroundNotification.
       */
      id<NSObject> _applicationDidEnterBackgroundObserver;
    }

    Представить это можно так:
    class Auth {
     class func auth() -> FIRAuth { ... }
     ...
    }
    
    class FIRAuth {
      var currentUser: FIRUser?
      ...
    }
    
    class FIRUser {
     var providerData: [Int : {что-то}]
     ...
    }
    
    Auth.auth().currentUser?.providerData[indexPath.row]


    Вопрос 2
    Кажется ещё более странным. Вы ведь знаете что такое опционал?! Тогда неужели Вы забыли, что метод может возвращать любое значение, в том числе и опционал. Теперь становится ясно, что с любым опционалом мы также можем применить опциональную цепочку, что собственно тут и было сделано.
    FUIAuth.defaultAuthUI() возвращает опционал. Почему бы и не продолжить цепочку. Продолжаем:
    FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication)
    Но как не странно этот метод тоже возвращает опционал и мы просто хотим себя от этого обезопасить и сказать, что если на последнем методе тоже будет опционал, то верни правую часть, то бишь false. В итоге получаем общую картину:
    FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false
    Ответ написан
    2 комментария
  • Как передать индекс ячейки для каждой из двух кнопок?

    doublench21
    @doublench21 Куратор тега Swift
    Смотря где вы обрабатываете нажатие? Внутри самой ячейки ?

    UPD
    Можно выкрутиться так: super.tableView.indexPath(for: self)
    НО это неправильный подход, Почитайте про MVC. Не нужно этого делать внутри ячейки.

    @IBAction func change(sender: UIButton) {
      
       for case let mycell as MyCustomCell in tableView.visibleCells where mycell.changeButton === sender {
          let indexPath = tableView.indexPath(for: myCell)
         // ...
       }
    
    }
    Ответ написан
  • Как в swift преобразовать кодироку строки?

    doublench21
    @doublench21 Куратор тега Swift
    let str = "Привет Как дела"  // Внутренняя кодировка Свифта utf-32
    
    let cp1251Data = str.data(using: .windowsCP1251) 
    let utf8Data = str.data(using: .utf8)
    
    cp1251Data.count // 15
    utf8Data.count // 28
    
    // ***********************************
    
    let session = URLSession.shared
    var URL = URL(string: "https://greatcomments.server/add")!
    var request = URLRequest(url: URL)
    request.httpMethod = "POST"
        
     // Headers
    request.addValue("application/x-www-form-urlencoded; charset=windows-1251", forHTTPHeaderField: "Content-Type")
    
    // Form URL-Encoded Body 
    let bodyParameters = [
         "comment": "Проверка",
    ]
    let bodyString = bodyParameters.queryParameters
    request.httpBody = bodyString.data(using: . win1251, allowLossyConversion: true)
    
    let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
          if (error == nil) {
            // Success
            let statusCode = (response as! HTTPURLResponse).statusCode
            print("URL Session Task Succeeded: HTTP \(statusCode)")
          }
          else {
            // Failure
            print("URL Session Task Failed: %@", error!.localizedDescription);
          }
        })
    task.resume()
    session.finishTasksAndInvalidate()
    
    
    // ***********************************
    
    protocol URLQueryParameterStringConvertible {
      var queryParameters: String {get}
    }
    
    extension Dictionary : URLQueryParameterStringConvertible {
      var queryParameters: String {
        var parts: [String] = []
        for (key, value) in self {
          let part = String(format: "%@=%@",
                            String(describing: key).win1251Encoded,
                            String(describing: value).win1251Encoded)
          parts.append(part as String)
        }
        return parts.joined(separator: "&")
      }
      
    }
    
    extension URL {
      func appendingQueryParameters(_ parametersDictionary : [String: String]) -> URL {
        let URLString : String = String(format: "%@?%@", self.absoluteString, parametersDictionary.queryParameters)
        return URL(string: URLString)!
      }
    }
    
    // Раньше Swift(Foundation) позволял любую строку закодировать в url-encode в любой кодировке. 
    // Сейчас же де факто это можно лишь сделать в utf-8. 
    // Видимо Apple аргументирует это тем,  что utf-8 - это стандарт в вебе. 
    
    // Да всех остальных случаев нужно писать такую функцию самому. 
    // Ниже кодировка в url-encode в windows-1251
    
    extension CharacterSet {
      static let rfc3986Unreserved = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~=&+")
    }
    
    extension String.Encoding {
      static let win1251 = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.windowsCyrillic.rawValue)))
    }
    
    extension String {
      func addingPercentEncoding(withAllowedCharacters characterSet: CharacterSet, using encoding: String.Encoding) -> String {
        let stringData = self.data(using: encoding, allowLossyConversion: true) ?? Data()
        let percentEscaped = stringData.map {byte->String in
          if characterSet.contains(UnicodeScalar(byte)) {
            return String(UnicodeScalar(byte))
          } else if byte == UInt8(ascii: " ") {
            return "+"
          } else {
            return String(format: "%%%02X", byte)
          }
          }.joined()
        return percentEscaped
      }
      
      var win1251Encoded: String {
        return self.addingPercentEncoding(withAllowedCharacters: .rfc3986Unreserved,  using: . win1251)
      }
    }
    Ответ написан
  • Как вызвать функцию из другого класса, которая без типа?

    doublench21
    @doublench21 Куратор тега Swift
    А Вы уверенны что знаете язык Swift? Судя по коду и вопросу - нет.
    Нужно понимать, что такое метод типа, а что такое инстанц метод.

    Метод типа определяется так. Ключевое слово static может быть заменено на class(но это не важно)
    class Printer {
      static func mustprint() {
        print ("was printed")
      }
    }


    И вызывается так
    Printer.mustprint()

    ----------

    А то что Вы написали, это инстанц метод
    class Printer {
       func mustprint() {
        print ("was printed")
      }
    }


    И вызывается он сначала путём создание инстанца этого класса, а затем вызова функции.
    let printer = Printer(); printer.mustprint()

    ----------

    О чём Вам тут и говорят: "Instance member 'mustprint' cannot be used on type 'Printer'; "
    Ответ написан
    3 комментария