• Почему не запускается CLI-проект с библиотекой SwiftyJSON?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Не ясно зачем нужен SwiftyJSON в 2019, но попробуйте в настройках xcworkspace изменить систему сборки на Legacy Build System
    Ответ написан
  • Как решить ошибку "unrecognized selector sent to instance"?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    5d10efdae0912561988174.png

    Код
    func playVideo(filename: String) {
        let path = Bundle.main.path(forResource: filename, ofType:"mp4")!
        player = AVPlayer(url: NSURL(fileURLWithPath: path) as URL)
    
        playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = CGRect(x: 880, y: 270, width: 960, height: 540)
        scene!.view!.layer.addSublayer(playerLayer)
    
        player.actionAtItemEnd = .none
        player.play()
    
    
    
        DispatchQueue.main.async {
          NotificationCenter.default.addObserver(self,
                                                 selector: #selector(playerItemDidReachEnd),
                                                 name: NSNotification.Name.AVPlayerItemDidPlayToEndTime ,
                                                 object: self.player.currentItem)
        }
      }
    
      @objc func playerItemDidReachEnd(notification: NSNotification) {
        print("repeating...")
    
        let seconds : Int64 = 0
        let preferredTimeScale : Int32 = 1
        let seekTime : CMTime = CMTimeMake(value: seconds, timescale: preferredTimeScale)
    
        player.seek(to: seekTime)
        player.play()
      }
    Ответ написан
  • Как правильно сделать структуру?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Простой пример:

    2ffZng2.png

    Код
    let json = """
        [{
        "invoiceNumber": "FV/MON/X/369",
        "date": "2019-06-01 00:00:00",
        "dueDate": "2019-06-01 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/368",
        "date": "2019-06-01 00:00:00",
        "dueDate": "2019-06-01 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/367",
        "date": "2019-06-01 00:00:00",
        "dueDate": "2019-06-01 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/366",
        "date": "2019-06-01 00:00:00",
        "dueDate": "2019-06-01 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/363",
        "date": "2019-05-04 00:00:00",
        "dueDate": "2019-05-04 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/362",
        "date": "2019-05-04 00:00:00",
        "dueDate": "2019-05-04 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/361",
        "date": "2019-05-04 00:00:00",
        "dueDate": "2019-05-04 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        },
        {
        "invoiceNumber": "FV/MON/X/360",
        "date": "2019-05-04 00:00:00",
        "dueDate": "2019-05-04 00:00:00",
        "overdue": true,
        "valueNoTax": 100,
        "valueWithTax": 123,
        "valueToPay": 123
        }]
        """
    
        struct FakturyObject: Decodable {
          let date: String
          let dueDate: String
          let invoiceNumber: String
          let overdue: Bool // <---- ОШИБКА БЫЛА ТУТ! 
          let valueNoTax: Int
          let valueToPay: Int
          let valueWithTax: Int
        }
    
        let data = json.data(using: .utf8)
        let decoder = JSONDecoder()
        let parsedData = try! decoder.decode([FakturyObject].self, from: data!)
    Ответ написан
  • Как исправить ошибку Declaration ‘pressesEnded(presses:withEvent:)’ has different argument labels from any potential overrides?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Ну Вам ведь даже сам Xcode пишет:
    Слушай, я вижу что такой метод есть, но почему-то у тебя отличаются названия агрументов. Может глянешь?


    Для Вас даже в Xcode есть встроенная документация - ⌘ + Shift + 0. Если ввести название этого метода и глянуть на аргументы, то становится ясно, что presses нужно заменить _ presses, а withEvent нужно заменить на with Тоже самое сделать и со вторым методом.

    func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?)


    P.S. Если Вы позиционируете себя iOS разработчиком, то как вы дальше та будете, если такая простая ошибка вызывает диссонанс.
    Ответ написан
  • Как сделать чтобы ScrollView скроллился до конца?

    varabeis
    @varabeis
    iOS разработчик, канал https://t.me/sparrowcode
    После открытия времени работы, нужно пересчитать contentSize у UIScrollView. Код, который вы привели, просто скрывает вьюхи.
    Ответ написан
  • Swift/Java vs React Native. В чем разница и куда лучше смотреть?

    RomReed
    @RomReed
    JavaScript, Flutter, ReactNative, Redux, Firebase
    Добрый день. У меня есть опыт разработки на реакт натив 2 года. Его самый большой плюс это скорость разработки(вам не нужно искать 2 разрабов для android и ios). Вы пишите код сразу на две платформы таких образом выкатываете приложение на рынок в очень короткие сроки. Но у него есть и минусы - его производительность будет уступать нативному приложению написанному на Swift/Java. В практике было пару раз что заказчик быстро выкатывает приложение на рынок. Потом его не устраивает производительность и приложение переписывается под Swift/Java.
    Ответ написан
  • На счет StoryBoard и чистого кода?

    yakovmanshin
    @yakovmanshin
    iOS Software Engineer
    1. Файлы .storyboard — это по сути XML-документы, в которых хранится структура интерфейса приложения. Если вы откроете сториборд в текстовом редакторе, то увидите что-то подобное:
    5cdf186b054f5546973533.png
    Код всех элементов хранится там. Но в реальной работе открывать исходный код сторибордов не требуется; элементы интерфейса подключаются к коду иначе — с помощью аутлетов и экшенов. Здесь вы найдете детальный гайд.

    2. Если вы только входите в разработку для iOS, изучите Intro to App Development with Swift и App Development with Swift — бесплатные учебники от Apple, которые очень доходчиво объясняют основные понятия и принципы, которые используются в разработке iOS-приложений.
    Познакомившись с базовыми концептами, переходите к более сложным вещам. На RayWenderlich.com можно найти много обучающих материалов по конкретным технологиям и фреймворкам (например, SpriteKit или Core Data), а также пошаговые инструкции о том, как реализовать определенные решения в коде (например, раскрывающийся экран now playing в Apple Music). За видеокурсы нужно платить, но текстовые туториалы доступны бесплатно.
    Моя претензия к RayWenderlich — там недостаточно теории и технических деталей, которые необходимо изучать, чтобы не только повторять чужие решения задач, но и создавать свои. Хорошие материалы по теории есть на Swift by Sundell, freeCodeCamp, ну и на Medium, конечно. Что касается базовых конструкций языка, много информации есть на Swift.org.
    Ответ написан
  • Синхронное выполнение кода SWIFT alamofire?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Добро пожаловать в мир DispatchQueue или OperationQueue на ваш выбор. Первый легче. Так как сама задача у вас является асинхронной, нужно будет немного поднапрячься. Для DispatchQueue нужно будет использовать барьеры, так как обычная serial очередь не подойдёт.

    Кидайте свои наработки, будем обсуждать дальше.
    Ответ написан
  • Почему view controller неактивен после перехода на него с другого view controller через navigation controller, используя custom animation transition?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Быть может в completion вашей анимации надо все же сказать системе, что анимация завершена.

    transitionContext.completeTransition(true)
    Ответ написан
  • Как решить проблему с авто размером collection view?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Потому-что, так никто не делает, ну кроме Вас. Для работы auto layout нужно построить цепочку ограничений сверху вниз.

    Что бы не спрашивать что у Вас есть, а что нет, сразу напишу полный список./

    1) Прописать у layout коллекции:
    // ...
    layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    layout.itemSize = UICollectionViewFlowLayout.automaticSize


    2) Соврал, нужно уточнение.

    pronunciationLabel - Сколько строк должен занимать? (Только одну?) Увеличивается только в ширину?
    wordLabel - Тоже, что и pronunciationLabel? Или увеличивается в высоту?

    3) Этот бред больше никогда не нужно делать.

    contentView.translatesAutoresizingMaskIntoConstraints = false
       
            NSLayoutConstraint.activate([
                contentView.leftAnchor.constraint(equalTo: leftAnchor),
                contentView.rightAnchor.constraint(equalTo: rightAnchor),
                contentView.topAnchor.constraint(equalTo: topAnchor),
                contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
            ])


    Уточнение получены. Продолжим.

    Для начала уточним, как нам добиться динамического размера вьюхи в ширину и высоту. Приведу простой и наглядный пример. Создам вьюхи и помещу туда два лейбла. Пишу всё исключительно кодом, т.к. не использую сториборд, но думаю свести проблем не составит. И так:

    5cab4bce2a9a6308684642.png
    Код текстом
    let v = UIView(frame: .zero)
    
        let l1 = UILabel(frame: .zero)
            l1.translatesAutoresizingMaskIntoConstraints = false
            l1.font = .systemFont(ofSize: 27.0)
            l1.text = "asdlas"
    
        v.addSubview(l1)
        NSLayoutConstraint.activate([
          l1.topAnchor.constraint(equalTo: v.topAnchor),
          l1.leadingAnchor.constraint(equalTo: v.leadingAnchor),
        ])
        l1.setContentHuggingPriority(.required, for: .vertical)
        l1.setContentCompressionResistancePriority(.required, for: .vertical)
    
        let trailing = l1.trailingAnchor.constraint(equalTo: v.trailingAnchor)
            trailing.priority = .defaultHigh
        NSLayoutConstraint.activate([
          trailing
        ])
    
        let l2 = UILabel(frame: .zero)
            l2.translatesAutoresizingMaskIntoConstraints = false
            l2.font = .systemFont(ofSize: 17.0)
            l2.text = ""
    
        v.addSubview(l2)
        NSLayoutConstraint.activate([
          l2.topAnchor.constraint(equalTo: l1.bottomAnchor),
          l2.leadingAnchor.constraint(equalTo: v.leadingAnchor),
        ])
        l2.setContentHuggingPriority(.required, for: .vertical)
        l2.setContentCompressionResistancePriority(.required, for: .vertical)
    
        let trailing_ = l2.trailingAnchor.constraint(equalTo: v.trailingAnchor)
            trailing_.priority = .defaultHigh
        let bottom = l2.bottomAnchor.constraint(equalTo: v.bottomAnchor)
            bottom.priority = .defaultHigh
        NSLayoutConstraint.activate([
          trailing_,
          bottom
        ])
    
    
        let s = v.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
    
        view.addSubview(v)
        v.frame.size = s
        v.center = view.center
        v.layer.borderColor = UIColor.red.cgColor
        v.layer.borderWidth = 1.0


    В принципе мы делаем обычные констрениты, задавая топ и лидинг. Примечателен тут другой момент, а именно трейлинг. Перед его заданием, мы обязательно установили св-ва сопротивление сжатию и сопротивления расстяжения обоим лейблам, давая тем самым системе понять, что хотим видеть лейбл ровно такой ширины, какой он есть на самом деле. После мы делаем констрейнт трейлинг и указываем ему приоритет немного ниже чем 1000(required). Кстати, быть может в сториборде приоритет снижать не придется. Проверьте. (Кажись система делаем это за вас)

    С шириной всё готово. Смотрим на костреинты для высоты. Тут вполне обычно, начинаем с топ. После нижний лейбл крепится к боттом первого. И снова небольшая магия. Последний нижний констрейнт снова с пониженным приоритетом. Кстати, быть может в сториборде приоритет снижать не придется. Проверьте. (Кажись система делаем это за вас)

    Если быть точнее снижая приоритет(по крайне мере если задавать их кодом) такой подход даёт понять системе, что высоту и ширину он прямиком и полностью должен расчитывать исходя из высоты и ширины его сабвьюх, а не назначить свои значения.

    Поглядим на примеры:
    Первая имеет меньший размер шрифта, но больше символов.
    HC2w483.png
    Первая имеет больший размер шрифта, но больше символов.
    5MhP2nj.png
    Первая имеет меньший размер шрифта, но меньше символов.
    V00A7Qc.png
    Первая имеет больший размер шрифта, но меньше символов.
    zXH8glH.png

    Как видимо размер вьюхи система посчитала вольностью верным. То есть мы динамически научились задавать высоту и ширину ячейки.

    Поехали дальше.

    Но для ячеек есть ещё одна небольшая проблема. Система лайаута коллекции имеет все нужные констреинты, но она ничего не знает о данных в этих ячеек. А ведь именно они задают ширину ячеейки. Для этого нам нужно в какой-то момент времени немного подсказать системе.

    Воспользуемся методом:
    5cab50033a6e2506454233.png
    Код текстом
    func preferredLayoutAttributesFitting(
        _ layoutAttributes: UICollectionViewLayoutAttributes
      ) -> UICollectionViewLayoutAttributes
      {
        let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
    
        let fittingSize = UIView.layoutFittingCompressedSize
    
        layoutAttributes.frame.size = systemLayoutSizeFitting(
          fittingSize,
          withHorizontalFittingPriority: .fittingSizeLevel,
          verticalFittingPriority: .fittingSizeLevel
        )
    
        return layoutAttributes
      }


    Так как все констреинты у нас настроены, нам осталась попросить систему подсчитать нужные размеры и передать новые размеры системе лайаута коллекции. В этот момент кстати, все данные ячейка уже получила. (Текст для лейблов)

    И малая ремарка, возможно в метод preferredLayoutAttributesFitting после вызова super. надо будет добавить вызов метода layoutIfNeeded(). А может и не нужно.

    Итого:
    Добавляем то, что в пункте 1.
    Устанавливаем нужные констреинты.
    Удаляем ваш код в пункте 3.
    Добавляем метод preferredLayoutAttributesFitting
    Ответ написан
  • Простой Hello World на Swift для вэб?

    Sanasol
    @Sanasol Куратор тега Веб-разработка
    нельзя просто так взять и загуглить ошибку
    html страница она и будет html страницей в любом случае. Фреймворк для этого не нужен.
    А что её отдать именно с помощью Swift надо поднять на нём сервер, и фреймворки здесь совсем не причём.
    Swift http server -> google
    https://github.com/httpswift/swifter

    Фреймворки типа Perfect, Vapor и др. -- не подойдут.

    https://github.com/Wolg/awesome-swift#http
    Ответ написан
  • Как преобразовать структуру Firebase в объект swift?

    doublench21
    @doublench21 Куратор тега Swift
    t.me/jeudesprits
    Что из перечисленного списка Вас смущает и Вы не умеете это делать: ?
    • Получить JSON данные через URLSession/Alamofire/FirebaseSDK
    • Использование Codable для преобразования JSON в класс/структуру
    Ответ написан
  • Как передать данные в кастомную ячейку UITableViewCell перед тем, как она будет построена?

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

    В делегате:
    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
      }
    Ответ написан
  • Как переместить файл из Assets в Documents?

    @badtrips Автор вопроса
    Получилось,

    let asset = NSDataAsset(name: "KanjiDataBase", bundle: Bundle.main)
            // получаем полный путь к каталогу Documents
            // объект класса NSURL
            let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
            if let documentUrl = urls.first {
                try! asset?.data.write(to: documentUrl.appendingPathComponent("KanjiDataBase.s3db"), options: [.atomic])
            }
    Ответ написан
  • Как сделать чтобы при повороте экрана Gradient был на весь экран?

    Vovanys
    @Vovanys
    просто размер вьюхи (self.view.bounds) надо изменять и перезапускать функцию

    нужно чтобы при перевороте экрана происходила перерисовка из-за изменений размеров вью
    if UIDevice.current.orientation.isPortrait {
    //тут перерисовка
    }
    Ответ написан