Git Hub
коротко
Ctrl + ↑ Позднее

SOLID

7 марта 2017, 12:19
  1. Single responsibility,
  2. Open-closed,
  3. Liskov substitution,
  4. Interface segregation
  5. Dependency inversion.

Single responsibility,

Принцип одной ответственности.

Open-closed

Модули, классы должны быть открыты для расширения и закрыты для изменения

Liskov — принцип подстановки

Подклассы не могут замещать поведение базового класса.
Подтипы должны дополнять базовые типы.

Собака не должна начать летать, вместо того чтобы лаять.

Interface segregation.

Разделение на интерфейсы.
Лучше иметь много маленьких интерфейсов которые отвечают за что-то одно, чем один большой универсальный интерфейс.

Dependency inversion. — Инверсия зависимостей

Модули верхних уровней не должны зависеть от модулей нижних уровней, и модули должны зависеть от интерфейсов а не от их конкретной реализации

Multithreads

6 марта 2017, 21:50

Создание низкоуровневого потока в 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

4 марта 2017, 14:03

Оглавление

  1. получаем токен устройства
  2. генерация фалов из сертификатов
  3. настраиваем серверную часть (PHP)
  4. меняем звук уведомления по умолчанию
  5. удаляем бейджи

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;

Ссылки:

Замена наследования делегированием

20 февраля 2017, 16:58

Проблема

У вас есть подкласс, который использует только часть методов суперкласса или не хочет наследовать его данные.

Решение

Создайте поле и поместите в него объект суперкласса, делегируйте выполнение методов объекту-суперклассу, уберите наследование.

Достоинства

Класс не содержит лишних методов, которые достались ему в наследство от суперкласса.
В поле-делегат можно подставлять разные объекты, имеющие различные реализации функциональности. По сути, вы получаете реализацию паттерна проектирования Стратегия.

Посчитать кол-во файлов в папке

13 февраля 2017, 15:28

Посчитать кол-во файлов в папке

ls -f . | wc -l
Nix   Unix

Рефакторинг

9 февраля 2017, 9:30

тут прям Антология рефакторинга
кто-то большой молодец.

Чистый код содержит необходимый минимум классов и других движущихся частей.

Чем меньше кода, тем меньше его нужно держать в голове. Чем меньше кода, тем меньше вероятность его сломать.

Протоколы и Универсальные типы в swift

8 февраля 2017, 16:29

Пример:
Создаём протокол 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 картинки

20 января 2017, 23:47

чтобы изменить цвет pdf картинки(иконки) в свойствах Render As надо выставить template
tintColor
backgroundColor

UI Testing на нескольких устройствах сразу

20 января 2017, 13:41

UI Тестирование приложений
bluepill

((https://github.com/linkedin/bluepill BluePill)

iOS: SwiftMonkey

20 января 2017, 12:28

Удобный фреймворк для UI тестирования
Эмитация обезьяны тапающей на все кнопки ;)

SwiftMonkey


Скачать тут

Swift: Audio

18 января 2017, 23:19

проигрывать кастомный звук

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   iOS   Swift

iOS: IBDesignable и IBInspectable

18 января 2017, 11:34

Пример класса

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()
    }
}

Полезный сайт

#iOS   iOS   Swift

Swift: Работа с датой

15 января 2017, 16:35

как можно пользоваться датой в 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
    }
}
#iOS   iOS   Swift

xcode: Создаём свой шаблон проекта для XCode

12 января 2017, 16:27

Создаём шаблон проекта на основе 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   iOS   xcode

XCode: создаём свой шаблон исходника

12 января 2017, 15:57

Создаём свой шаблон файла
1 шаг.

$ mkdir -p ~/Library/Developer/Xcode/Templates/[Group name]
$ cp -R /Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Templates/Source/Swift\ File.xctemplate ~/Library/Developer/Xcode/Templates/[Group name]/

Смотрим что получилось

2 шаг.

$ cd ~/Library/Developer/Xcode/Templates/Custom/Swift\ File.xctemplate
$ ls
TemplateIcon.png          TemplateIcon@2x.png       TemplateInfo.plist        ___FILEBASENAME___.swift

3 шаг. Редактируем исходный файл ___FILEBASENAME___.swift

//
//  ___FILENAME___
//  ___PROJECTNAME___
//
//  Created by ___FULLUSERNAME___ on ___DATE___.
//___COPYRIGHT___
//

import UIKit

4 шаг. переименовываем папку Swift File.xctemplate -> UIKitFile


Swift: Generics (Дженерики)

12 января 2017, 14:09

Пример 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)

11 января 2017, 15:01

Интересная штука инъекция кода в запущенном приложении

на github


Паттерн Chain of Responsability

11 января 2017, 12:11

Оглавление

Цепочка обработчиков

Цепочка обязаностей, она же цепочка ответственности, она же цепочка обработчиков

Когда использовать этот паттерн:

  • У вас более чем один объект — обработчик.
  • У вас есть несколько объектов обработчика, при этом вы не хотите специфицировать который объект должен обрабатывать в даный момент времени.

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


Ctrl + ↓ Ранее