• Какой мобильный кроссплатформенный фреймворк посоветуете?

    doublench21
    @doublench21
    Хоть разработчики кроссплатформенного г*%на и будут гореть в аду(кроме разработчиков VSCode), но лучшим вариантом на данный момент является React Native. Для справки, нынешний Инстаграмм сделан на React Native. Ближайшим пресоедователем, набирающим обороты является Flutter .

    5VuVjGP.png

    P.S. Всё остальное забудьте как страшный сон!
    Ответ написан
    6 комментариев
  • Как вывести информацию с class в php?

    doublench21
    @doublench21
    Потому что для начала нужно создать объект этого класса!!!
    <?php 
    require_once('Config.php');
    $config = new Config();
    echo $config->vk_id;
    Ответ написан
    1 комментарий
  • Как исправить ошибку Declaration ‘pressesEnded(presses:withEvent:)’ has different argument labels from any potential overrides?

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


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

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


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

    doublench21
    @doublench21
    1. iOS process list: github в Гугл. Что-то может и сработает, но вряд ли на iOS11/12/13.
    2. Можете написать в твиттер ему. Один из лучших iOS исследователей. Он уже такое пытался
    Ответ написан
    Комментировать
  • Почему в Swift вижу чаще использование let, чем var?

    doublench21
    @doublench21 Куратор тега Swift
    Иммутабельность переменной - это достаточно важное свойство. Переменные нужно помечать ключевым словом let не просто так. Опустим очевидное, исходящее из определения - неизменяемость. Но что стоит за этим на уровне компилятора? А стоят за этим нужные вещи.

    Если мыслить широко, то ключевым словом let можно ведь пометить не только, скажем переменную содержащую число, а коллекцию или структуру или объект.

    Коллекция, помеченная как неизменяемая, даёт возможность компилятору выделить для неё непрерывную память, что позволит ускорить операцию чтения, в сравнении с обычной, динамической коллекцией. (Именно по этой причине, для особых нужд, в Swift, есть специальная коллекция ContiguousArray)

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

    Сравнение для неизменяемых объектов также может быть оптимизировано компилятором.

    Даже у обычных структур, методы которые изменяют поля структуры, нужно помечать ключевым словом mutable В свою очередь это делает тоже не просто так.
    Ответ написан
    Комментировать
  • Как транслировать C-функцию в JS?

    doublench21
    @doublench21
    Сверяем:
    C
    KPG48QZ.png

    JS
    1QdRgtT.png


    Получаем:
    https://www.npmjs.com/package/crc-full
    Ответ написан
    Комментировать
  • В чем отличие данной записи с дженериком и без?

    doublench21
    @doublench21 Куратор тега Swift
    Два типа Anyи AnyObject являются так называемыми Nonspecific types. Неспецифичные типы служат указателем компилятору о возможности хранения любого типа. НО за такую возможность нужно платить и Вы платите:

    Во-первых отсутствием информации о типе на момент компиляции, вы не можете вызвать, скажем некоторое св-во у String, даже зная, что присвоенная переменная на самом деле является типом String. У вас просто не будет такой информации ровно до тех пор, пока вы не преобразуете этот тип обратно.
    Конечно во время выполнения Swift прекрасно понимает, какой именно тип находится в переменной типа Any, но это только во время выполнения кода, на момент компиляции информация об этом отсутсвует.

    Во-вторых вы платите скоростью, при работе с такими типами. У компилятора нету информации о типе, а значит он не может произвести необходимые оптимизации.

    Функция print(_:separator:terminator:) получает информацию о том, что вывести в консоль, исходя из того, что все стандартные типы реализуют протоколы CustomStringConvertible, CustomDebugStringConvertible,CustomReflectable в реализации которых содержится информация о типе(текстовая). Если у типа нет реализации этих протоколов, print(_:separator:terminator:) выводит просто название типа.

    Более того, вы всегда можете вывести так называемый дамп у абсолютного любого типа в консоль посредством функции dump(_:name:indent:maxDepth:maxItems:).

    За более подробной информации о всех возможностях и разновидностях функций для работы с Debugging and Reflection можно глянуть тут

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

    Дженерики же - это просто заместители(placeholders) типов. На момент компиляции, компилятор вместе вашего заместителя, скажем T подставит конкретный тип, скажем String. Что в свою очередь приводит к тому, что у дженериков отсутствуют проблемы указанные выше. (Даже моё "во-первых" у дженериков отсутствуют, если вы накладываете на них ограничения. )

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

    P.S. На самом деле Дженерики одна из самых прекрасных и Сильных сторон языка Swift, и моя жалкая попытка вам пояснить - не объясняет должном счётом ничего. Изучайте их.
    Ответ написан
    Комментировать
  • Минимальный набор знаний для разработчика iOS?

    doublench21
    @doublench21
    Вы приводите в пример сервисы на основе Spring, только я не пойму, причём тут iOS?

    Напишу оба варианта.

    Back-end:
    1) Знать Swift(очевидно)
    2) Знать Vapor
    3) Знать Swift Package Manager
    4) Знать NIO
    5) Знать Foundation
    6) Знать Dispatch

    Front-end iOS Client:
    1) Знать Swift(очевидно)
    2) Знать UIKit
    3) Знать Foundation
    4) Знать Dispatch
    5) Знать Core Data
    6) Знать CocoaPODS(хотя любые менеджеры зависимостей считаю по большей части бесполезными в разработке клиента, ибо 80% работы - это работа интерфейса, где конкретных и нужных тебе решений крайне мало. Легче написать самому, а может и не легче, но лучше бы...)

    * Сортировка в порядке важности.
    Ответ написан
    3 комментария
  • Синхронное выполнение кода SWIFT alamofire?

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

    Кидайте свои наработки, будем обсуждать дальше.
    Ответ написан
    Комментировать
  • Как правильно реализовать градиент в tableview cell?

    doublench21
    @doublench21 Куратор тега Swift
    При всём моём к вам уважении, у меня глаза из орбит вылезли.

    В свой день рождения я не буду ругаться, а постараюсь задать вам вопросы для более ясной картины. И так:

    1) В курсе ли вы как работает жизненный цикл ячеек таблицы/коллекции? Судя по коду, предположу, что есть небольшие непонятки.

    2) Работа с асинхронностью в данном контексте тоже абсолютно бесполезна. Вы просто тратите время на переключения контекста.
    Помню вы хотели начать изучать асинхронность. Начали, но есть снова непонятки? Судя по коду.

    Ответьте на эти вопросы и далее мы затронем сам градиент.

    Эти два вопроса так же прилично тормозят ваш код.

    Ответы получены. Двигаемся дальше.

    1) Представьте себе что у вас ячейки высотой в 100, а вся таблица высотой в 500. Получаем 5 видимых ячеек. Таблица крайне экономно использует память телефона и на самом деле инстанцирует примерно видимое количество ячеек плюс 1-2 про запас для плавной прокрутки. Итого мы имеем 7 ячеек, которые вне зависимости сколько вы прописываете в дата соурс , будь то 50, использоваться для всех 50 будут лишь эти 7.

    Метод же cellForItem вызывается для всех ячеек которые должны появиться. То есть это больше видимых снова и снова при скролле. То есть очень часто и много.

    Этот метод должен быть настолько быстрым насколько это возможно и должен быть практически чистым от лишнего кода.

    Надеюсь теперь ясно что глаза из орбит вылезли не зря, глядя на то, что сделали Вас.

    Выводы.

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

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

    2) Асинхронность нужно использовать для затратных по времени операций. Достать значения из массива такой очевидно не является. Асинхронно нужно получать данные. В вашем случае, всю асинхронность уберите полностью.

    3) Уберите весь код по обновлению данных ячейки внутрь самой ячейки. Создайте метод, скажем func configure(...) и вызывайте аккуратно в методе cellForItem.

    4) Попробуйте выставить градиенту(слою) св-во shouldRasterize в true. При этом так же добавьте rasterizationScale = UIScreen.main.scale
    Ответ написан
    8 комментариев
  • Каким образом можно запросить только заголовки URL?

    doublench21
    @doublench21 Куратор тега Swift
    Ну вообще говоря для того, что бы получить лишь заголовки ответа сервера, достаточно сказать самому серверу, что бы он отдал только заголовки. Для этой цели существует Head запрос(не Post с Get едины)

    И да, Alamofire такие очевидные штуки тоже умеет.
    public enum HTTPMethod: String {
        case options = "OPTIONS"
        case get     = "GET"
        case head    = "HEAD"
        case post    = "POST"
        case put     = "PUT"
        case patch   = "PATCH"
        case delete  = "DELETE"
        case trace   = "TRACE"
        case connect = "CONNECT"
    }
    Ответ написан
    Комментировать
  • Почему session_start() выдает ошибку?

    doublench21
    @doublench21
    Предположу, что выше приложенного кода всё равно что-то есть. Быть может HTML. Попробуйте вставить в самую первую строчку файла: <?php session_start();?>
    Ответ написан
    1 комментарий
  • Невозможно зайти на сайт с IPhone, в чем может быть проблема?

    doublench21
    @doublench21
    У вас проблемы с настройкой сервера для http2.

    https://serverfault.com/questions/937253/https-doe...

    Гуглите:
    http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [upgrade], value: [h2]


    Это видимо связано со специфичной OpenSSL на платформе iOS/macOS. Хром же на macOS видимо использует внутреннюю версию и открывает без проблем.

    Выхлоп:

    curl https://ladnydom.ru/ --verbose
    *   Trying 92.53.100.223...
    * TCP_NODELAY set
    * Connected to ladnydom.ru (92.53.100.223) port 443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
    * successfully set certificate verify locations:
    *   CAfile: /etc/ssl/cert.pem
      CApath: none
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Client hello (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: CN=www.ladnydom.ru
    *  start date: Sep 18 00:00:00 2018 GMT
    *  expire date: Oct 18 12:00:00 2019 GMT
    *  subjectAltName: host "ladnydom.ru" matched cert's "ladnydom.ru"
    *  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=Thawte RSA CA 2018
    *  SSL certificate verify ok.
    * Using HTTP2, server supports multi-use
    * Connection state changed (HTTP/2 confirmed)
    * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
    * Using Stream ID: 1 (easy handle 0x7fe049800400)
    > GET / HTTP/2
    > Host: ladnydom.ru
    > User-Agent: curl/7.54.0
    > Accept: */*
    > 
    * Connection state changed (MAX_CONCURRENT_STREAMS updated)!
    * http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [upgrade], value: [h2]
    * HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
    * Closing connection 0
    * TLSv1.2 (OUT), TLS alert, Client hello (1):
    curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
    Ответ написан
    6 комментариев
  • Интерактивная 3D модель в IOS App?

    doublench21
    @doublench21
    Смотря что вы используете для отображения 3D модели. Если Scenekit, то конечно - да.
    Ответ написан
  • Почему view controller неактивен после перехода на него с другого view controller через navigation controller, используя custom animation transition?

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

    transitionContext.completeTransition(true)
    Ответ написан
    1 комментарий
  • Может ли использовать iOS SDK для какого-нибудь сайта во всех типах приложений на Swift?

    doublench21
    @doublench21 Куратор тега Swift
    Какой ещё к чёрту сайт?! Если написано iOS - это означает только одно... использование внутри приложения под iOS.

    Сайты пишут на HTML/CSS/JS, причём тут Swift и iOS не ясно. Бэкенд на Swift не имеет никакого отношения к визуальной составляющей.
    Ответ написан
  • Как сделать кастомизированную панель навигации в приложении для iOS?

    doublench21
    @doublench21 Куратор тега Swift
    Возможно всё!

    В гугле куче статей на эту тему. Сделайте свои подклассы UITabBarController/UITabBar/UITabBarItem. Переопределите нужные методы, добавьте нужные сабвью.

    А что касается переходов, это достаточно большая тема, но опять таки, она хорошо расписана. У делегата UITabBarControllerDelegate, есть два метода отвечающие за переход:
    https://developer.apple.com/documentation/uikit/ui...
    https://developer.apple.com/documentation/uikit/ui...

    Каждый из этих методов должен вернуть соответсвующий аниматор. Как создавать такие? Куча статей.
    Ответ написан
    Комментировать
  • Изучение iOS-разработки и дизайна мобильных приложений. Как быть?

    doublench21
    @doublench21 Куратор тега Swift
    Привет из Ташкента. Дизайн мобильных приложений или таки разработка мобильных приложений? Разные ипостаси.

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

    Просто пойми, что для новичка не имеет никакого смысла бояться выбрать что-то неправильное или потерять время. Ты сейчас изучаешь языки, конструкции, подходы. В конце концов формируешь своё мышление.

    Если ответ на первый вопрос утвердительный и макбук таки будет, то смело скачивай книжку по Swift от Apple. Устанавливай Swift на Linux и начинай приключение в мир нового для тебя языка.
    Ответ написан
  • Интерактивный drag & drop борд?

    doublench21
    @doublench21
    Самый быстрый и рабочий вариант это коллекция с кастомным лайаутом. Коллекция как и таблица поддерживает встроенный механизм drag and drop.

    Если ничего из этого никогда не делали, можете посмотреть последнии доступные лекции от Стэнфорда по iOS. Под конец там реализуют канвас с перетаскиванием. На русском вроде только в текстовом варианте можно найти.
    Ответ написан
  • Как решить проблему с авто размером collection view?

    doublench21
    @doublench21 Куратор тега Swift
    Потому-что, так никто не делает, ну кроме Вас. Для работы 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
    Ответ написан
    3 комментария