Swift
hitTest
Задача
У вас есть UIView c N количеством кнопок внутри
и вот прикол, высота этой вьюхи 1 пиксель,
а теперь вопрос как вы обработаете Tap'ы по каждой из кнопок ?
решение 1
//MARK: hitTest override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if buttonOne.frame.contains(point){ return buttonOne } else if buttonOne.frame.contains(point){ return buttonTwo } else if buttonOne.frame.contains(point){ return buttonThree } else { return nil } }
решение 2 (более приятное)
//MARK: hitTest override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { return getButton(point, buttons: [buttonOne, buttonTwo, buttonThree]) } func getButton(_ point:CGPoint, buttons: [UIView] ) -> UIView? { for button in buttons { if (button.frame.contains(point)){ return button } } return nil }
GestureRecognizer
let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) greenButton.addGestureRecognizer(singleTap)
Vapor
Vapor пример
import Vapor let drop = Droplet() drop.get("/"){ request in var items:[String]=[String]() items.append("Andrey") items.append("Yuriy") items.append("Kirill") items.append("Alexey") items.append("Alexandr") return try JSON(node: items) } drop.run()
Команда сборки
vapor build
на этапе сборки мы можем увидеть ошибки, если мы накосячили
vapor run
Swift: Случайное число
// random let randomValue:UInt32 = (arc4random_uniform(100)) // от 0 до 100
Нашёл клёвую конструкцию
typealias Animation = (TimeInterval, ()->Void)
let animation: Animation = (5.0, { })
internal class Node<T> { var data: T var next: Node<T>? init(data: T){ self.data = data } } internal struct Queue<T> { var first, last: Node<T>? mutating func dequeue() -> T? { let pop = first?.data first = first?.next if first == nil { last = nil } return pop } mutating func enqueue(data: T){ if last == nil { first = Node(data: data) last = first } else { last?.next = Node( data: data) last = last?.next } } }
var animations: Queue = Queue<Animation>()
Анимация прямо в playground.
Чтобы поиграться с анимацией не создавая проект приложения достаточно использовать playground

import UIKit import PlaygroundSupport let containerView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 375.0, height: 667.0)) let circle = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 50.0, height: 50.0)) circle.center = containerView.center circle.layer.cornerRadius = 25.0 let startingColor = UIColor(red: (253.0/255.0), green: (159.0/255.0), blue: (47.0/255.0), alpha: 1.0) circle.backgroundColor = startingColor containerView.addSubview(circle); let rectangle = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 50.0, height: 50.0)) rectangle.center = containerView.center rectangle.layer.cornerRadius = 5.0 rectangle.backgroundColor = UIColor.white containerView.addSubview(rectangle) UIView.animate(withDuration: 2.0, animations: { () -> Void in let endingColor = UIColor(red: (255.0/255.0), green: (61.0/255.0), blue: (24.0/255.0), alpha: 1.0) circle.backgroundColor = endingColor let scaleTransform = CGAffineTransform(scaleX: 5.0, y: 5.0) circle.transform = scaleTransform let rotationTransform = CGAffineTransform(rotationAngle: 3.14) rectangle.transform = rotationTransform }) PlaygroundPage.current.liveView = containerView
Segue
очень полезный метод для того чтобы передать данные в любой ViewController
override func prepare(for segue: NSStoryboardSegue, sender: Any?) { if segue.identifier == "segueAdd" { print("segue Add") // тут передаём всё что нам нужно в ViewController который будет вызван при переходе } if segue.identifier == "segueEdit" { print("segue Edit") } }
Стоит использовать в связке с presentingViewController для конфигурации родительского контроллера...
presentingViewController.someProps = someValues
Swift: динамическое создание класса
protocol Runable { init() } class AdvHandler: Runable{ required init(){ } func run(){ print("run class is runnable()") } } func createInstance<T>(typeThing:T.Type) -> T where T:Runable { return typeThing.init() }
Смысл этого подхода в том что метод createInstance понятия не имеет что за класс он создаёт для клиента.
это открывает большие возможности абстрагирования.
Повышая уровень абстракции.
Применение
let a = createInstance(typeThing: AdvHandler.self) as AdvHandler a.run()
macOS: Модальное окно из NSViewController
Модальное окно из NSViewController
let aboutVC = self.storyboard?.instantiateController(withIdentifier: "AboutVC") as! NSViewController self.presentViewControllerAsModalWindow(aboutVC )
Multithreads
Создание низкоуровневого потока в swift
var thread = pthread_t(bitPattern: 0) var attr = pthread_attr_t() pthread_attr_init(&attr) callbacks = [ { } ] pthread_create(&thread, &attr, { pointer in print("test") return nil }, nil)
Создание глобальной очереди
DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async { self.workTask() { self.printResult() } }
Push Notifications
Оглавление
- получаем токен устройства
- генерация фалов из сертификатов
- настраиваем серверную часть (PHP)
- меняем звук уведомления по умолчанию
- удаляем бейджи
APNS — Apple Push Notification Service
1. получить токен устройства
для этого в файл AppDelegate.swift добавляем два метода
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. let notifyCenter = UNUserNotificationCenter.current() notifyCenter.delegate = self notifyCenter.requestAuthorization(options: [.sound, .alert, .badge]){ (granted, error) in print("ok: \(granted)") print("err: \(error)") } application.registerForRemoteNotifications() return true } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let token = PushNotifyHelper.getTokenFromDeviceToken(deviceToken) print("Registration device token: \(token)") }
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { print("Handle push from foreground") // custom code to handle push while app is in the foreground print("\(notification.request.content.userInfo)") } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { print("Handle push from background or closed") // if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background print("\(response.notification.request.content.userInfo)") }
PushNotifyHelper
import UserNotifications class PushNotifyHelper { class func getTokenFromDeviceToken(_ deviceToken: Data) -> String{ var token = "" for i in 0..<deviceToken.count { token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]]) } return token } }
3. Настраиваем серверную часть (PHP)
$deviceToken = "0000000000000000000000000000000000000000000000000"; class PushSender{ static public function run($deviceToken){ $certificateFile = "push.pem"; $certificateString = file_get_contents('push.pem'); $port = 2195; $host = "gateway.sandbox.push.apple.com"; $address = "ssl://{$host}:{$port}"; $title = "title"; $message = "Privet"; $arMessage = array( 'aps' => array( 'alert' => array( 'title' => $title, 'body' => $message, ), 'url-args' => array( '', ), 'sound'=>'default' ), ); $error = 0; $errorString = ""; $context = $streamContext = stream_context_create(); $path = tempnam(sys_get_temp_dir(), 'cert_'); file_put_contents($path, $certificateString); stream_context_set_option($streamContext, 'ssl', 'local_cert', $path); $client = @stream_socket_client( $address, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $context ); $encodedPayload = json_encode($arMessage); $binaryData = chr(0). chr(0). chr(32). pack('H*', $deviceToken). chr(0).chr(strlen($encodedPayload)). $encodedPayload; fwrite($client, $binaryData); fclose($client); } } PushSender::run($deviceToken);
для примера я сделал анти-рефакторинг и объединил несколько разных классов в один метод нарушив сразу несколько парадигм ООП. но сделал это чтобы не размазывать код, а попытаться наглядно показать объём который нужен для отправки уведомлений с сервера на iOS устройства.
5. удаляем бейджи )
UIApplication.shared.applicationIconBadgeNumber = 0;
Протоколы и Универсальные типы в swift
Пример:
Создаём протокол Alfa, c методами, которые реализуются через generics в дальнейшем
protocol Alfa { associatedtype Item func printItem(from item: Item) func make() -> Item }
Пишем реализацию класса Betta, который поддерживает протокол Alfa
protocol Initalizable { init() } class Betta<Item: Initalizable>: Alfa { func printItem(from item: Item) { print("\(item)") } func make() -> Item { return Item() } }
class Window: Initalizable { required init() { } var isOpened = false convenience init(_ opened: Bool) { self.init() isOpened = opened } } class CellWin: Initalizable { var name: String = "" required init() { } }
Само использование и конфигурация класса Betta совершенно различными классами, но с общими протоколами
let item = Betta<CellWin>() item.printItem(from: CellWin() ) let factory = Betta<Window>() factory.printItem(from: Window(true)) let window = factory.make() print("\(window)")
изменить цвет pdf картинки
чтобы изменить цвет pdf картинки(иконки) в свойствах Render As надо выставить template
tintColor
backgroundColor


