#iOS
всё что связано с приложения под iOS и их интеграцией с сайтами и интернет магазинами
Generamba: как использовать ?
пример rambafile
### Headers settings company: adeveloper ### Xcode project settings project_name: SkillViperT xcodeproj_path: SkillViperT.xcodeproj ### Code generation settings section # The main project target name project_target: SkillViperT ### project_file_path: SkillViperT/Modules ### Templates templates: #- {name: local_template_name, local: 'absolute/file/path'} #- {name: remote_template_name, git: 'https://github.com/igrekde/remote_template'} #- {name: catalog_template_name} - {name: swifty_viper}
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 } }
xcode: Создаём свой шаблон проекта для XCode
Создаём шаблон проекта на основе Single Application View
1 Шаг.
Идём в /Applications
правой кнопокой на приложении XCode и пункт Show Package Content
и заходим в папку Cmd+G ->
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application/
Копируем папку Single Application View и вставляем её по пути
~/Library/Developer/Xcode/Templates/[Templates group name]
Если вы это делаете в первый раз то папки Custom у вас нет и её надо создать
2 шаг. Меняем идентификатор шаблона в файле TemplateInfo.plist
iOS: Code Injection (on runtime)
iOS: VIPER архитектура
Сделай настолько просто, насколько это возможно, но не проще.
(с)Альберт Эйнштейн
признаки хорошей архитектуры:
- сбалансированное распределение обязанностей между сущностями с жесткими ролями;
- тестируемость. Обычно вытекает из первого признака (без паники, это осуществимо при соответствующей архитектуре);
- простота использования и низкая стоимость обслуживания.
VIPER
Разделение обязанностей — это очень хорошо
View: отвечает за отображение данных на экране и оповещает Presenter о действиях
пользователя. Пассивен, сам никогда не запрашивает данные, только получает их от
презентера.
Interactor: содержит всю бизнес-логику, необходимую для работы текущего модуля.
Presenter: получает от View информацию о действиях пользователя и преображает ее
в запросы к Router’у, Interactor’у, а также получает данные от Interactor’a,
подготавливает их и отправляет View для отображения.
Entity: объекты модели, не содержащие никакой бизнес-логики.
Router: отвечает за навигацию между модулями.
Carthage: менеджер зависимостей
Carthage: менеджер зависимостей, как о нём говорят «простой и безжалостный»
carthage version
Cartfile — простой текстовый файл, который описывает зависимости Вашего проекта для Carthage, таким образом, он определяет, что устанавливать. Каждая строка в Cartfile указывает, откуда извлечь зависимость, имя зависимости, и при необходимости, какая версия зависимости используется. Cartfile аналогичный файлу Podfile в CocoaPods.
| Cartfile — создаём любым блокнотом
touch Cartfile
open -a Xcode Cartfile
github "CocoaLumberjack/CocoaLumberjack"
carthage update --platform iOS
iOS: как эмитировать неполадки с сетью в Simulator'e на XCode
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)
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: Изменить цвет векторной картинки 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) })
iOS: Модальные окна
закрытие модального окна
dismiss(animation:true,nil)
чтобы окно-всплывашка была поверх текущего окна
- выставляем цвет у View backgound: Clear Color
- у ViewController указыаем presentation: Over Current Context
let frame:CGRect = CGRect(x: 50, y: 30, width: 200, height: 300) self.view.frame = frame
ставим рамку и цвет рамки у PopUp окна
override func viewDidLayoutSubviews() { ... self.view.layer.borderWidth = 1 self.view.layer.borderColor = UIColor.black.cgColor }
получаем контроллер из Storyboard программно
let SpecialViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SpecialViewController") as! SpecialViewController
Аналог foreach в Objective-C
По массиву можно пробежать обычным for
пример:
//arItems - это массив NSArray содержащий элементы типа NSString for (NSString *item in arItems){ NSLog(@" item:%@",item); }
Конкатенация строк
NSString *tmpText = [NSString stringWithFormat:@"%@\n%@",_txtView.text,_txtMessage.text];
Публичная переменная класса
@public NSString *message;
Выход из приложения похоже уже не применяют, но тем не менее он делается так
exit(EXIT_SUCCESS);