Swift
Swift: Audio
проигрывать кастомный звук
import AVFoundation /// example: /// player = AudioHelper() /// player.prepare("r2d2") /// player.playSound() class AudioHelper { private var player = AVAudioPlayer() func prepare(name:String){ let path = Bundle.main.path(forResource: name, ofType: "mp3") let url = URL(fileURLWithPath: path!) do { self.player = try AVAudioPlayer(contentsOf: url) self.player.prepareToPlay() } catch{ print("error plaing sound") } } func playSound() { player.play() } }
let player = AudioHelper() player.prepare("r2d2") player.playSound()
iOS: IBDesignable и IBInspectable
Пример класса
import UIKit @IBDesignable class UIViewDes: UIView { @IBInspectable var borderColor: UIColor = UIColor.clear{ didSet{ layer.borderColor = borderColor.cgColor } } @IBInspectable var borderWidth:CGFloat = 1 { didSet{ layer.borderWidth = borderWidth } } @IBInspectable var corderRadius: CGFloat = 0 { didSet{ layer.cornerRadius = corderRadius } } override func awakeFromNib() { super.awakeFromNib() } }
Swift: Работа с датой
как можно пользоваться датой в swift
// форматируем дату строку формата "dd.mm.yyyy" func getDate() -> String{ let formatter = DateFormatter() formatter.dateFormat = "dd.mm.yyyy" let date = formatter.string(from: dateEnd as Date) return date }
/// Хелпер для работы с датами class DateHelper { /// преобразует строку вида YYYY-MM-DD -> NSDate /// /// - Parameter dateStr: строка формата YYYY-MM-DD /// - Returns: NSDate class func dateFromString (dateStr: String) -> NSDate? { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let date = dateFormatter.date(from: dateStr) return date as NSDate? } // форматируем дату строку формата "dd.mm.yyyy" class func toString(date:Date, format:String) -> String{ let formatter = DateFormatter() formatter.dateFormat = format let dateResult = formatter.string(from: date as Date) return dateResult } }
ещё вариант в виде extension
extension Date { static func from(_ value: String) -> Date? { let dateFormatter = DateFormatter() // doc: http://userguide.icu-project.org/formatparse/datetime dateFormatter.dateFormat = "dd.MM.yyyy" if let newDate = dateFormatter.date(from: value) { return newDate } else { return nil } } // форматируем дату строку формата "dd.mm.yyyy" func to(format:String) -> String { let formatter = DateFormatter() formatter.dateFormat = format let dateResult = formatter.string(from: self) return dateResult } }
Swift: Generics (Дженерики)
Пример Generics в функции
class GenericsDemo { class func swap<T>(_ a: inout T,_ b: inout T){ let temp = a a = b b = temp } } var n1 = 100 var n2 = 200 GenericsDemo.swap(&n1, &n2) var s1 = "s1" var s2 = "s2" print("s1=\(s1) <-> s2=\(s2)") GenericsDemo.swap(&s1, &s2) print("swap\ns1=\(s1) <-> s2=\(s2)")
Genereics в типах
protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct TOS<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } var tos = TOS<String>() tos.push("Swift") println(tos.items) tos.push("Generics") println(tos.items) tos.push("Type Parameters") println(tos.items) tos.push("Naming Type Parameters") println(tos.items)
iOS: Code Injection (on runtime)
Паттерн Fabric Method
Фабричный метод
Фабричный метод порождает объекты одного и того же типа.
import Foundation import UIKit // Protocol for "Product" protocol AppleProduct { var name: String {get set} var screenSize: Double {get set} var price: Double {get set} func getProduct() -> String } // Protocl for "Creator" protocol AppleProductCreator { func createProduct() -> AppleProduct } // Class for "ConcreteProduct" class IPhoneProduct: AppleProduct { var name: String = "iPhone 6" var screenSize: Double = 4.7 var price: Double = 199.00 func getProduct() -> String { return "Apple product "(name)", with screen size in (screenSize) inch, at proce: $(price)" } } class IPadProduct: AppleProduct { var name: String = "iPad Air 3" var screenSize: Double = 10.1 var price: Double = 499.00 func getProduct() -> String { return "Apple product "(name)", with screen size in (screenSize) inch, at proce: $(price)" } } // Class for "ConcreteCreator" class IPhoneProductCreator: AppleProductCreator { static let sharedInstance:IPhoneProductCreator = IPhoneProductCreator() func createProduct() -> AppleProduct { return IPhoneProduct() } } class IPadProductCreator: AppleProductCreator { static let sharedInstance:IPadProductCreator = IPadProductCreator() func createProduct() -> AppleProduct { return IPadProduct() } }
Применение
let product1: AppleProduct = IPhoneProductCreator.sharedInstance.createProduct() print("Got a new device: " + product1.getProduct()) let product2: AppleProduct = IPadProductCreator.sharedInstance.createProduct() print("Got a new device: " + product2.getProduct())
Пример 2
protocol Currency { func symbol() -> String func code() -> String } class Euro : Currency { func symbol() -> String { return "€" } func code() -> String { return "EUR" } } class UnitedStatesDolar : Currency { func symbol() -> String { return "$" } func code() -> String { return "USD" } } enum Country { case unitedStates, spain, uk, greece } enum CurrencyFactory { static func currency(for country:Country) -> Currency? { switch country { case .spain, .greece : return Euro() case .unitedStates : return UnitedStatesDolar() default: return nil } } }
Применение
let noCurrencyCode = "No Currency Code Available" CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode
CoreData: Получение контекста
Получение контекста managedObjectContext в CoreData
Каждый объект хранимый в CoreData имеет ссылку на контекст
let context = someCoreDataItem.managedObjectContext
Паттерн Iterator
Пример
//: Playground - noun: Паттерн Iterator import UIKit struct BanksLevel{ let price:Double let time:UInt32 let comment:String } struct Levels { let arLevels: [BanksLevel] } struct LevelsIterator: IteratorProtocol { private var current = 0 private let levels: [BanksLevel] init(levels: [BanksLevel]) { self.levels = levels } mutating func next() -> BanksLevel? { defer { current += 1 } return levels.count > current ? levels[current] : nil } } extension Levels: Sequence { func makeIterator() -> LevelsIterator { return LevelsIterator(levels: arLevels) } }
Применение
let arLevels = Levels(arLevels: [ BanksLevel(price: 1.06740, time: 1, comment: "Первый банковский уровень"), BanksLevel(price: 1.06210, time: 2, comment: "Второй банковский уровень") ] ) for level in arLevels { print("Определён: \(level)") }
Пример 2
import UIKit class Item{ let name:String init(_ name:String){ self.name = name } } class IteratableItems{ var arItems: [Item] = [] init(items:[Item]){ self.arItems = items } } class ItemIterator: IteratorProtocol{ private var current = 0 private let arItems: [Item] init(items:[Item]){ self.arItems = items } func next()-> Item?{ defer { current += 1 } return arItems.count > current ? arItems[current] : nil } } extension IteratableItems: Sequence { func makeIterator() -> ItemIterator { return ItemIterator(items: arItems) } }
Используем:
let arItems = IteratableItems(items: [Item("One"),Item("Two"),Item("Three")]) for item in arItems{ print("item: \(item.name)") }
Carthage: менеджер зависимостей
Carthage: менеджер зависимостей, как о нём говорят «простой и безжалостный»
carthage version
Cartfile — простой текстовый файл, который описывает зависимости Вашего проекта для Carthage, таким образом, он определяет, что устанавливать. Каждая строка в Cartfile указывает, откуда извлечь зависимость, имя зависимости, и при необходимости, какая версия зависимости используется. Cartfile аналогичный файлу Podfile в CocoaPods.
| Cartfile — создаём любым блокнотом
touch Cartfile
open -a Xcode Cartfile
github "CocoaLumberjack/CocoaLumberjack"
carthage update --platform iOS
Swift: Проверяем интернет соединение
Всегда в приложениях работающих с сетью стоит проверять наличие сети.
import Foundation import SystemConfiguration public class CheckInternet { class func isConnectedToNetwork() -> Bool { var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) zeroAddress.sin_family = sa_family_t(AF_INET) let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) { $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress) } } var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0) if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false { return false } let isReachable = flags == .reachable let needsConnection = flags == .connectionRequired return isReachable && !needsConnection } }
if (CheckInternet.isConnectedToNetwork() == true) { ... // есть интернет } else{ ... // у вас нет интернета }
Swift: Animation
Анимацию элементов сделать довольно не сложно
Скрытие элементов
let step1 = 0.5 let step2 = 1.0 let step3 = 1.5 UIView.animate(withDuration: step1, animations: { self.labelDate.alpha = 0 self.view.layoutIfNeeded() }) UIView.animate(withDuration: step2, animations: { self.labelLevelUP.alpha = 0 self.view.layoutIfNeeded() }) UIView.animate(withDuration: step3, animations: { self.labelLevelDN.alpha = 0 self.view.layoutIfNeeded() })
Показ элементов
func showUI(){ let step1 = 1.0 let step2 = 2.0 let step3 = 3.5 UIView.animate(withDuration: step3, animations: { self.labelDate.alpha = 1 self.view.layoutIfNeeded() }) UIView.animate(withDuration: step2, animations: { self.labelLevelUP.alpha = 1 self.view.layoutIfNeeded() }) UIView.animate(withDuration: step1, animations: { self.labelLevelDN.alpha = 1 self.view.layoutIfNeeded() }) }
просто изменяем прозрачность, иногда можно использовать задержку, в основном потоке чтобы не заморачиваться с дочерними, вызвав функцию sleep(в секундах)
sleep(3)
Перемещение объектов
uiViewedObject.view.center = CGPoint(x,y)
Swift: Загружем из XIB файла
UIView
let cell = Bundle.main.loadNibNamed("MenuCellDefault", owner: self, options: nil)?.first as! MenuCellDefault
MenuCellDefault — имя xib файла
загрузка nib файла
такой вариант подходит для UIView производных, но не годится для UIViewController
UIViewController
let globalTasksVC = GlobalTasksVC(nibName: "GlobalTasksVC", bundle: nil) self.present(globalTasksVC, animated: true, completion: nil)
Swft: uiAlertView
Пример 1
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil)
Пример 2
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default){ UIAlertAction in print("close") }) self.present(alert, animated: true, completion: { print("show AlertMessage") })
Swift: Unit Test
Тесты
Правила написания тестов:
- Тестируем одно поведение (один тест тестирует одно поведение)
для того чтобы протестировать свои классы приложения нужно добавить в начало файла с тестами
@testable import PrjoectNameApp
где PrjoectNameApp — имя вашего iOS приложения/проекта
Памятка по методам
Всегда ошибка
XCTFail(@"always failed")
Равенство базовых типов
let primitive1:Int = 5 let primitive2:Int = 5 XCTAssertEqual(primitive1, primitive2) }
Равенство с погрешностью базовых типов
let constOne:Float = 5.012 let constTwo:Float = 5.014 let accuracy:Float = 0.005 XCTAssertEqualWithAccuracy(constOne, constTwo, accuracy: accuracy)
—-
Проверка на nil
id foo = nil; XCTAssertNil(foo, @"pointer:%p", foo);
—-
Проверка с задержкой по времени
XCTestExpectation *expectation = [self expectationWithDescription:@"block not call"]; NSTimeInterval timeout = 1.0f; [expectation performSelector:@selector(fulfill) withObject:nil afterDelay:0.3f]; [self waitForExpectationsWithTimeout:timeout handler:nil];
Тест асинхронного взаимодействия
func testNetModel(){ var items:[Post] = [] let expect = expectation(description: "Test net Model") let model = NetModel() model.npGetList({ posts in items = posts expect.fulfill() }) waitForExpectations(timeout: 4.0, handler: { error in if let error = error { XCTFail(error.localizedDescription) } let isLoaded:Bool = (items.count > 1) XCTAssertTrue(isLoaded) if isLoaded == false { print("posts: \(items)") } }) }
—-
Swift: читаем куки
просто читаем куки
func readCookies(){ if let cookies = HTTPCookieStorage.shared.cookies { for cookie in cookies { print("\n\n\(cookie)\n\n") } } }
ставим куки к запросу
... let request = NSMutableURLRequest(url: url! as URL) let cookies = HTTPCookieStorage.shared.cookies for cookie in cookies! { request.setValue(cookie.value, forHTTPHeaderField: cookie.name) } webView.delegate = self webView.loadRequest(request as URLRequest)
Swift: выполнить код в основном потоке
DispatchQueue.main.async { let urlSmallImage = "https:" + smallImage.string! let url = NSURL(string: urlSmallImage) let data = NSData(contentsOf:url! as URL) self.profilePhoto.image = UIImage(data:data! as Data) }
Swift: преобразование опционального типа к строгому
(imageOption?.description)!
let imageOption = value[0].dictionary!["photo"]?.dictionary?["src"]?.dictionary?["small"] let imageSmall = "https:" + (imageOption?.description)!
Swift: Изменить цвет векторной картинки pdf
Часто требуется изменить цвет отрисовки контурной иконки, в Swift 3 это делается так
let logo = UIImage(named: "Home") let imageView = UIImageView(image:logo) imageView.image = imageView.image!.withRenderingMode(.alwaysTemplate) imageView.tintColor = UIColor.white self.navigationItem.titleView = imageView
UIButton: скруглёные края
layer.cornerRadius Number 10 layer.masksToBounds Boolean Yes
Нельзя просто так взять и обновить UI, когда пришел ответ с сервера
Нельзя просто так взять и обновить UI, когда пришел ответ с сервера
Программисты с опытом ObjC могут посмеяться над этой «ловушкой», потому что она должна быть общеизвестна: методы, связанные с UI, безопасно дергать только из главного потока. Иначе — непредсказуемость и баги, толкающие в тотальный ступор. Но это наставление почему-то проходило мимо меня, пока я, наконец, не столкнулся с жуткими багами.
Пример «проблемного» кода:
func fetchFromServer() { let url = NSURL(string:urlString)! NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { data, response, error in if (error != nil) { ... } else { self.onSuccess(data) } })!.resume() } func onSuccess(data) { updateUI() }
Обратите внимание на блок completionHandler — все это будет исполняться вне главного потока! Тем, кто еще не столкнулся с последствиями, советую не экспериментировать, а просто не забыть обставить updateUI следующим образом:
func onSuccess(data) { dispatch_sync(dispatch_get_main_queue(), { updateUI() }) }
DispatchQueue.main.sync(execute: { let item = arRecords[indexPath.row] as TaskModel detailVC.setDataSource(item: item) })