$ grep -r Tag: «шпаргалки»

-rw-r--r-- 2.1K 11 апр. 2024 · FC685FE · ~1 мин

Создание DMG файла в терминале

dmg code snippets шпаргалки bash

Создание DMG-файла через Терминал

Вам когда-нибудь нужно было упаковать ваше приложение для распространения на macOS? Решение проще, чем вы думаете, и оно прямо у вас под рукой в Терминале. Недавно я наткнулся на удобную bash-функцию, которая упрощает создание DMG (Disk Image) файла. Вот как её настроить:

Шаг 1: Редактирование профиля

nano ~/.zprofile

Шаг 2: Добавление bash-функции

Затем вставьте следующую функцию в ваш .zprofile. Этот скрипт использует встроенную в macOS команду hdiutil для создания файловой системы HFS+ внутри DMG-файла.

dmg(){
    hdiutil create -fs HFS+ -srcfolder "$1" -volname "$2" "$2.dmg"
}

Шаг 3: Сохранение и применение изменений в профиле

После добавления кода сохраните изменения и выйдите из `nano`. Чтобы функция стала доступна немедленно без перезапуска терминала, примените конфигурацию вашего профиля:

source ~/.zprofile

Шаг 4: Использование функции

Теперь вы можете легко создавать DMG-файл для любой папки или приложения. Например, чтобы создать DMG для 'ModulbankInformer.app', просто выполните:

dmg ModulbankInformer.app ModulbankInformer

Эта команда создаст файл ModulbankInformer.dmg с содержимым директории ModulbankInformer.app.

Вот и всё — быстрый и эффективный способ создания DMG-файлов прямо из вашего Терминала!

[↵] открыть пост creating-a-dmg-file-from-terminal.md
-rw-r--r-- 1.4K 4 апр. 2024 · 0427246 · ~1 мин

Middleware для роутинга в Vapor 4 для обрезания слеша в url

vapor code snippets шпаргалки swift server side swift

Для веб-сайта или бэкенда — обычное дело, когда такие URL, как mySite.com/webpage и mySite.Com/webpage/, ведут на одну и ту же страницу. Для поисковых систем это разные адреса. Чтобы избежать дублирования контента, можно добавить простую middleware, которая будет удалять завершающий слеш и перенаправлять пользователя.

Вот пример кода для такого класса middleware в Vapor 4:

final class TrimSlashInPathMiddleware: Middleware {
    func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> {
        if request.url.path.count > 1, request.url.path.hasSuffix("/") {
            let newPath = String(request.url.path.trimmingSuffix(while: { $0 == "/" }))
            let response = request.redirect(to: newPath, redirectType: .permanent)
            return request.eventLoop.makeSucceededFuture(response)
        }
        return next.respond(to: request)
    }
}

Просто добавьте его в файл configure.swift:

import Vapor

public func configure(_ app: Application) throws {
    app.middleware.use(TrimSlashInPathMiddleware())

    app.http.server.configuration.port = 8081

    try routes(app)
}

Работает с Vapor 4.92.5.

[↵] открыть пост a-middleware-for-vapor4-to-trim-a-slash-in-url-path.md
-rw-r--r-- 1.9K 29 марта 2020 · C1C7EDD · ~1 мин

Оборачиваем модели в SwiftUI для соответствия Identifiable

swiftui swift шпаргалки

Чтобы использовать массив моделей во вью List в SwiftUI, эти модели должны соответствовать протоколу Identifiable.

Вот пример модели:

struct MyDataModel {
    let title: String
    let message: String
} 

А вот пример вью SwiftUI, в котором хотим показать список:

struct TestView: View {
    var dataArray: [MyDataModel]
    var body: some View {
        List(dataArray) { data in
            VStack {
                Text(data.title)
                Text(data.message)
            }
        }
    }
} 

Если использовать MyDataModel внутри List, Xcode выдаст ошибку:

Ошибка соответствия Identifiable в Xcode

Иногда модель просто так не поменять. Например, она может быть из стороннего SDK, который вы используете в приложении. Но можно написать обёртку для этой структуры, которая соответствует протоколу Identifiable:

struct MyDataModelWrapper: Identifiable {
    var id = UUID()
    var data: MyDataModel
}

let testDataModel = MyDataModel(
    title: "Title 1",
    message: "I wanna be used inside of a List"
)

let wrappedData = MyDataModelWrapper(data: testDataModel)

Тогда вью будет выглядеть так:

struct TestView: View {
    var dataArray: [MyDataModelWrapper] 

    some View {
        List(dataArray) { wrappedData in
            VStack {
                Text(wrappedData.data.title)
                Text(wrappedData.data.message)
            }
        }
    }
}

Готово.

[↵] открыть пост wrapping-models-in-swiftui-for-identifiable-conformance.md
-rw-r--r-- 1013B 10 сент. 2019 · 64BE02E · ~1 мин

GitHub Actions как CI для Swift-проекта

swift github ci шпаргалки

Github Actions

Конфиг workflow для GitHub Actions, который собирает Swift-проект. В примере собирается проект на Vapor с помощью Swift 5.0.3 на Ubuntu 18.04:

name: Ubuntu 18.04 Swift 5.0.3

on: [push]

jobs:
  build_on_ubuntu:
    runs-on: ubuntu-18.04

    steps:
    - name: Install dependencies
      run: sudo apt-get update; sudo apt-get install -yq libssl-dev zlib1g-dev

    - name: Checkout
      uses: actions/checkout@master

    - name: Download Swift
      run: curl https://swift.org/builds/swift-5.0.3-release/ubuntu1804/swift-5.0.3-RELEASE/swift-5.0.3-RELEASE-ubuntu18.04.tar.gz --output swift.tar.gz

    - name: Unpack Swift
      run: |
          tar xzf swift.tar.gz
          mv swift-5.0.3-RELEASE-ubuntu18.04 swift

    - name: Swift build
      run: |
          export PATH=$(pwd)/swift/usr/bin:"${PATH}"
          swift build -c release
[↵] открыть пост using-github-actions-as-ci-for-building-swift-project.md
-rw-r--r-- 567B 5 сент. 2017 · E5E50B4 · ~1 мин

openssl и Vapor 2

vapor swift шпаргалки

Столкнулся с тем, что перестал компилиться проект на Ubuntu на Vapor 2. Точнее, одна из зависимостей - Crypto. Оказалось, что из-за добавленного репозитория, в котором были более новые версии некоторых библиотек, оно и не компилилось. Запишу сюда - пришлось даунгрейдиться:

apt install libssl-dev=1.0.2g-1ubuntu4.10
apt install openssl=1.0.2g-1ubuntu4.10
[↵] открыть пост openssl-i-vapor-2.md
-rw-r--r-- 2.5K 3 мая 2017 · 6BC24C7 · ~2 мин

Weak delegate в Swift 3

swift шпаргалки утечки памяти

Memory usage in Xcode

Боролся тут с утечками памяти в рабочем проекте. Копание привело к тому, что после ухода из UIViewController далеко не вся память освобождается. Если несколько раз открывать этот UIViewController, возвращаться назад и снова открывать - потребляемая память растёт и не очень слабо освобождается.

Суть проблемы оказалась в протоколах и делегатах. Классическая ошибка. У меня в UIViewController используется UICollectionView с кастомной ячейкой, у которой есть делегат. Мой UIViewController является для каждой ячейки делегатом. Пример реализации протокола и делегата в интернете и книге по Swift выгядит примерно так:

// Protocol
protocol MyCollectionViewCellDelegate {
    func someFunc()
}

// UICollectionViewCell
final class MessageCollectionViewCell: UICollectionViewCell {
    var delegate: MyCollectionViewCellDelegate?
}

// UIViewController
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // some code....
    cell.delegate = self
}

Внутри объекта ячейки у нас strong-ссылка ;на делегата (UIViewController), в результате происходит утечка памяти.

Решение простое - сделать слабую ссылку (weak) для delegate. Для этого придётся указать протоколу, что реализовать его сможет только класс. Структуры уже пролетают, но и нужны в структурах нет. Меняется всё так:

// Protocol
protocol MyCollectionViewCellDelegate: class {
    func someFunc()
}

// UICollectionViewCell
final class MessageCollectionViewCell: UICollectionViewCell {
    weak var delegate: MyCollectionViewCellDelegate?
}

После этих простых изменений всё стало прекрасно - после возвращения назад из UIViewController использование памяти возвращается на исходный уровень.

[↵] открыть пост weak-delegate-v-swift-3.md
-rw-r--r-- 611B 28 окт. 2016 · 7DC1233 · ~1 мин

Анимация-«тряска» для UIView

шпаргалки swift
// MARK: - Расширение UIView (или NSView)
extension UIView {

    /// Анимация-«тряска»
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.rotation")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 1.0
        animation.values = [-Double.pi / 6, Double.pi / 6, -Double.pi / 6, Double.pi / 6, -Double.pi / 7, Double.pi / 7, -Double.pi / 8, Double.pi / 8, 0.0 ]

        layer.add(animation, forKey: "shake")
    }

}

myView.shake()

[↵] открыть пост shake-effekt-dlya-uiview.md
-rw-r--r-- 1.1K 26 сент. 2016 · 55D7D8F · ~1 мин

Элегантный extension для Notification.Name в Swift 3

swift шпаргалки

В новой версии Swift 3 теперь другой конструктор для NSNotification (теперь уже просто Notification, префикс NS отбросили):

struct Config {
    static let ShouldCloseBrowserNotification = "ShouldCloseBrowserNotification"
}

let notification = Notification(
    name: Notification.Name(rawValue: Config.ShouldUpdateDialogNotification),
    object: nil,
    userInfo: nil
)
NotificationCenter.default.post(notification)

Выглядит параметр name не очень то красиво теперь. Зато можно расширить Notification.Name, чтобы было красиво:

extension Notification.Name {
    static let shouldCloseBrowserNotification = Notification.Name("ShouldCloseBrowserNotification")
}

let notification = Notification(
    name: .ShouldUpdateDialogNotification,
    object: nil,
    userInfo: nil
)
NotificationCenter.default.post(notification)

Примерно так же сделано и в самом UIKit:

Код UIKit

[↵] открыть пост elegantnyj-extension-dlya-notification-name-v-swift-3.md
-rw-r--r-- 763B 18 авг. 2016 · 14091F5 · ~1 мин

Блок (замыкание) как свойство класса в Swift

swift шпаргалки

Пример использования блока (замыкания) как свойства класса в Swift.

class ChatViewController: UIViewController {

    private var someClosure: (() -> Void)?
    private var anotherClosure: ((arg: Double) -> Bool)?

    func executeClosures() {
        if self.someClosure != nil {
            self.someClosure()
        }

        if self.anotherClosure != nil {
            let boolResult = self.anotherClosure(arg: 2.0)
        }
    }

    func addSelfClosure(closure: (() -> Void)!) {
        self.someClosure = closure
    }

    func printSomething() {
        self.addSelfClosure() {
            print("closure called")
        }
        self.executeClosures() // prints: closure called
    }

} 
[↵] открыть пост blok-zamykanie--kak-svojstvo-klassa-v-swift.md
-rw-r--r-- 3.1K 12 авг. 2016 · EC7C9DE · ~2 мин

Кастомный бейдж для UITabBarController на Swift

swift шпаргалки uitabbarcontroller

Шёл 2016 год, а для того, чтобы изменить цвета для бейджа внутри таба всё ещё необходимо создавать свой UI-элемент и добавлять его в таббар вручную. Работающее решение на Swift:

// MARK: - UITabBarController extension for badges
extension UITabBarController {

    /**
    Set badges

    - parameter badgeValues: values array
    */
    func setBadges(badgeValues: [Int]) {

        for view in self.tabBar.subviews {
            if view is CustomTabBadge {
                view.removeFromSuperview()
            }
        }

        for index in 0...badgeValues.count-1 {
            if badgeValues[index] != 0 {
                addBadge(
                    index: index,
                    value: badgeValues[index],
                    color:UIColor.yellowColor(),
                    font: UIFont.systemFontOfSize(11)
                )
            }
        }

    }

    /**
    Add badge for tab

    - parameter index: index of tab
    - parameter value: badge value
    - parameter color: badge color
    - parameter font: badge font
    */
    func addBadge(index: Int, value: Int, color: UIColor, font: UIFont) {
        let badgeView = CustomTabBadge()

        badgeView.clipsToBounds = true
        badgeView.textColor = UIColor.whiteColor()
        badgeView.textAlignment = .Center
        badgeView.font = font
        badgeView.text = String(value)
        badgeView.backgroundColor = color
        badgeView.tag = index
        tabBar.addSubview(badgeView)

        self.positionBadges()
    }

    override public func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.tabBar.setNeedsLayout()
        self.tabBar.layoutIfNeeded()
        self.positionBadges()
    }

    /**
    Positioning
    */
    func positionBadges() {

        var tabbarButtons = self.tabBar.subviews.filter { (view: UIView) -> Bool in
            return view.userInteractionEnabled // only UITabBarButton are userInteractionEnabled
        }

        tabbarButtons = tabbarButtons.sort({ $0.frame.origin.x < $1.frame.origin.x })

        for view in self.tabBar.subviews {
            if view is CustomTabBadge {
                let badgeView = view as! CustomTabBadge
                self.positionBadge(badgeView, items:tabbarButtons, index: badgeView.tag)
            }
        }
    }

    /**
    Position for badge

    - parameter badgeView: badge view
    - parameter items: tab bar buttons array
    - parameter index: index of tab
    */
    func positionBadge(badgeView: UIView, items: [UIView], index: Int) {

        let itemView = items[index]
        let center = itemView.center

        let xOffset: CGFloat = 12
        let yOffset: CGFloat = -14
        badgeView.frame.size = CGSizeMake(17, 17)
        badgeView.center = CGPointMake(center.x + xOffset, center.y + yOffset)
        badgeView.layer.cornerRadius = badgeView.bounds.width/2
        tabBar.bringSubviewToFront(badgeView)
    }

}

/// Custom UILabel class for badge view
class CustomTabBadge: UILabel {}
[↵] открыть пост kastomnyj-bejdzh-dlya-uitabbarcontroller-na-swift.md
-rw-r--r-- 1.2K 9 авг. 2016 · FDC24F3 · ~1 мин

Функция задержки на Swift

swift шпаргалки

Очень приятный синтаксический сахар - функция для запуска кода с задержкой через Grand Central Dispatch с помощью dispatch_after:

Update 2024. Swift 5.5+

Если нужна задержка внутри async-функции:
func someMethod() async throws {
    // sleep for 2 seconds
    try await Task.sleep(nanoseconds: NSEC_PER_SEC * 2)
}

Swift 2:

/**
Delay function using GCD. Syntax sugar.

- parameter delay: delay in seconds
- parameter closure: closure code to execute after delay
*/
func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
    dispatch_get_main_queue(), closure)
}

Swift 3:

/**
Delay function using GCD. Syntax sugar.

- parameter delay: delay in seconds
- parameter closure: closure code to execute after delay
*/
func delay(_ delay: Double, closure:()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

Использование:

delay(0.4) {
    // код
}
[↵] открыть пост funktsiya-zaderzhki-na-swift.md
-rw-r--r-- 877B 14 июня 2016 · B548F4B · ~1 мин

Модальный UIVIewController с прозрачностью

swift шпаргалки

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

Выставляем в Storyboard для Segue поле Kind как «Present Modally». Для UIViewController, который показываем, выставляем цвет фона Clear Color, делаем внутри фон (картинка или другой UIView) со значением alpha, например, 0.5.

В коде:

self.performSegueWithIdentifier("segueName", sender: self)

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "segueName" {
        let vc = segue.destinationViewController as! YourViewController
        vc.modalPresentationStyle = .Custom
    }
}
[↵] открыть пост modal-nyj-uiviewcontroller-s-prozrachnost-yu.md
-rw-r--r-- 1.8K 12 мая 2016 · 6FA87ED · ~1 мин

Тестирование асинхронного кода в XCTest

swift xctest тесты шпаргалки

Пока писал тесты в приложении, столкнулся с тем, что не работают тесты, в которых есть асинхронный код. Например, если мы делаем асинхронный запрос в сеть и callback-блоке проверяем то, что получилось. Проверки просто не выболнялись и Xcode говорил, что тест удачно пройден, даже если он заведомо не должен пройти.

В ходе гугления оказалось два решения - одно через семафоры из Grand Central Dispatch, воторое с помощью expectations. С expectations мне понравилось больше. Пример теста:

import XCTest

class apiClientTests: XCTestCase {
    override func setUp() {
        super.setUp()
    }

    override func tearDown() {
        super.tearDown()
    }

    /**
    SampleTest
    */
    func testSampleAsyncRequest() {
        let exp = expectationWithDescription("\(#function)\(#line)")

        APIClient.sharedInstance.someMethod { (responseObject, error) in
            XCTAssertNotNil(responseObject, "responseObject should not be nil")
            XCTAssertNil(error, "error should be nil")

            exp.fulfill()
        }

        waitForExpectationsWithTimeout(40) { (error) in
            if error != nil {
                XCTAssertTrue(false)
            }
        }
    }
}

P.S. - если хочешь, чтобы тесты запускались в определённом порядке - то надо помнить, что они запускаются тупо в алфавитном порядке. То есть надо именовать тесты test1Name, test2Name и т.д.

[↵] открыть пост testirovanie-asinhronnogo-koda-v-xctest.md
-rw-r--r-- 1.3K 11 мая 2016 · 61AD73C · ~1 мин

Заметка про Socket.IO-Client-Swift

socket.io swift шпаргалки

Небольшая шпаргалка - для socket.io есть клиент на Swift. Казалось бы, на гитхабе хорошо расписано, как его использовать. Вот только к моему бэкенду на Node.js он никак не хотел подключаться с кодом примеров.

Логи показывали (если пробовать через polling-запросы), что клиент стучится по адресу /engine.io и получает 404 ошибку. Изучение браузерной Javascript-библиотеки, которая с этим же бэкендом работает без каких-либо танцев с бубном, показало, что надо указать другой путь - /socket.io. Благо, для этого есть специальная опция.

Итого, получаем:

let socketURL = NSURL(string: "http://localhost:3000")
let socket = SocketIOClient(socketURL: socketURL!, options: [
    .ForceWebsockets(true),
    .Path("/socket.io/"),
    .ConnectParams(["token": "token"])
])

socket.on("connect") {data, ack in
    print("socket connected")
}

socket.connect() 
[↵] открыть пост zametka-pro-socket-io-client-swift.md
-rw-r--r-- 370B 22 апр. 2016 · 4E22F08 · ~1 мин

Конвертирование UTC даты с миллисекундами из String в NSDate на Swift

swift шпаргалки

Чтобы перевести дату из текста в NSDate из немного нестандартного вида с миллисекундами:

let dateString = "2016-04-22T17:42:46.762+03:00"

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

let myDate = dateFormatter.dateFromString(dateString) 
[↵] открыть пост konvertirovanie-utc-daty-s-millisekundami-iz-string-v-nsdate.md
-rw-r--r-- 1.0K 18 апр. 2016 · E93D4A7 · ~1 мин

Лог-функция для Swift с выводом файла, метода и строки

шпаргалки swift полезное

Функция-шпаргалка для логирования в Swift:

import Foundation

/**
 Лог-функция с выводом файла, метода и строки, откуда вызывается. 
 Пример использования: DLog("привет")

 - parameter messages: тексты/объекты, которые надо вывести
 - parameter fullPath: путь до файла, который вызывается
 - parameter line: номер строки в файле
 - parameter functionName: название метода/функции вызова
*/
func DLog(messages: Any..., fullPath: String = #file, line: Int = #line, functionName: String = #function) {
     let file = NSURL.fileURLWithPath(fullPath)
     for message in messages {
          print("\(file.pathComponents!.last!):\(line) -> \(functionName) \(message)")
     }
}

// Пример:
DLog("message 1", "message 2")
// YourClass.swift:42 -> someMethod() message 1
// YourClass.swift:42 -> someMethod() message 2
[↵] открыть пост log-funktsiya-dlya-swift-s-vyvodom-fajla-metoda-i-stroki.md
-rw-r--r-- 1.8K 6 апр. 2016 · EF30922 · ~1 мин

Простой console.log с выводом файла и номера строки в Node.js

node.js javascript полезное шпаргалки

Пока кодю на Node.js нужно постоянно что-то выводить в консоль. Например, ошибки. Но для большей информативности удобнее знать, где именно ошибка выводится. Тем более, что пока кодил под iOS такой удобный макрос всегда был под рукой, а с Node.js пришлось погуглить и поковыряться, т.к. многие примеры со Stack Overflow просто падали на последней версии Node.js 5.10.0. Падали из-за использования в них Error.captureStackTrace(err, arguments.callee), а сейчас уже нужно использовать NFE.

В итоге сделал то, что хотел. Оставлю тут как шпаргалку.

npm install colors --save

Файл logger.js:

'use strict';

let colors = require('colors');
colors.enabled = true;

exports.p = function logger(somethingForPrint) {
    somethingForPrint = somethingForPrint || '';
    const originalPrepareStackTrace = Error.prepareStackTrace;

    Error.prepareStackTrace = (error, stack) => { return stack; };

    let e = new Error;
    Error.captureStackTrace(e, logger);

    const stack = e.stack;
    const filename = stack[0].getFileName().split('/').reverse()[0];
    const trace = filename + ':' + stack[0].getLineNumber() + " " + colors.bold.black('%s') + "\n";

    Error.prepareStackTrace = originalPrepareStackTrace;

    console.log(trace, somethingForPrint);
}; 

Использовать:

const logger = require('../utils/logger');
logger.p('something happened');
// file.js:401 something happened 
[↵] открыть пост prostoj-console-log-s-vyvodom-fajla-i-nomera-stroki-v-node-js.md
-rw-r--r-- 865B 24 марта 2016 · 75B06AF · ~1 мин

Восстановление слетевшего загрузчика GRUB на Hetzner

шпаргалки hetzner grub ubuntu linux

Второй раз за 2-3 года уже сталкиваюсь с тем, что на Hetzner на одном сервака слетает GRUB. Как следствие, после ребута сервер недоступен. Приходится идти в панель управления, в разделе Rescue включать загрузку с образа восстановления, цепляться к нему по SSH и восстанавливать загрузчик. Искать каждый раз инфу не классно, коротко после того, как подключились по ssh к системе восстановления, вводим в консоли:

mount /dev/md3 /mnt
chroot-prepare /mnt
chroot /mnt
mount -a
apt-get install grub2
grub-install /dev/sda
update-grub
exit
reboot now
[↵] открыть пост vosstanovlenie-sletevshego-zagruzchika-grub-na-hetzner.md
-rw-r--r-- 1.7K 14 окт. 2015 · 1821E8C · ~1 мин

Баг Xcode 7 с [NSLocalizableString length]

шпаргалки баги xcode

В Xcode 7 есть баг с локализацией, при котором приложение падает, вызывая много много раз [NSLocalizableString length]. У меня в проекте я словил его в связи с тем, что некоторые xib'ы у меня лежали вне папки самого проекта в папке Base.lproj. В итоге каждый раз, когда что-то загружалось в приложении из этих xib'ов - происходило падение без внятной причины. Причём в последнем Xcode 6 всё было прекрасно. Разрулить удалось переименовав Base.lproj в en.lproj и добавив в проект файлы заново из этой папки.

Ещё пара решений есть на Stack Overflow, суть та же, просто некоторым помогло просто включить/выключить галочку Use Base Localization либо отметить у файла Storyboard английский язык, но это скорее для тех, у кого весь UI внутри Storyboard нарисован. Есть ещё тема на форуме разработчиков Apple.

Причём баг, похоже, давно в 7 версии Xcode, в бетах тоже, по-моему, наблюдался. В текущей версии 7.01 присутствует. Надеюсь исправят в ближайшем будущем.

[↵] открыть пост bag-xcode-7-s-nslocalizablestring-length-.md
-rw-r--r-- 2.5K 23 июля 2015 · BB014D8 · ~2 мин

Пара слов про Parse.com

parse.com javascript rest шпаргалки кодировка

Ковырял тут кое-что на Parse. В двух словах - штука очень крутая, есть крутые SDK для разных платформ, в том числе можно на Javascript юзать их как на фронт-энде, так и на бэкенде. Можно прям у них в облаке написать на node.js его, даже можно Express подключить, если нужно. Но есть два но:

  1. Когда ты создаёшь отложенный push notification с расписанием - ты указываешь время отправки. Так вот через Javascript SDK он выставляет его по GMT и всё. Всем пуш будет отправлен по GMT вне зависимости от их часовой зоны, просто по расписанию. Указать, что ты хочешь отправить push всем, например, в 19:00 местного времени, чтобы клиент в любом часовом поясе получил сообщение в свои 19:00, в Javascript SDK ты не можешь. Этому багу уже 2 года. Вместо этого, тебе предлагается использовать из Javascript их REST API (sic!).
  2. Окей, ты используешь REST API, благо это можно из того же Javascript SDK удобно сделать, и всё работает как надо, пуши планируются по местному времени, но... В тексте заголовка из сообщения вырезаются все русские буквы. Во всех примерах в документации к REST API просят указать заголовок запроса "Content-Type: application/json", вот только этого мало, чтобы кириллица и прочие символы не из латиницы не вырезались, оказывается, нужно указать кодировку в заголовке: "Content-Type: application/json; charset=utf-8". Чёрт его знает, в какой кодировке они ожидают по умолчанию данные, выкатывая международный сервис, но тем не менее.

А в остальное, конечно, сервис очень классный.

[↵] открыть пост para-slov-pro-parse-com.md
-rw-r--r-- 2.6K 10 июля 2015 · 02CABEA · ~2 мин

Сборка iOS проекта из консоли через xcodebuild

ios xcodebuild шпаргалки

Оставлю себе шпаргалку, как сделать на bash скрипт, который соберёт тебе проект в ipa файл.

В папке с исходниками iOS-проекта делаем папку, например, scripts, в нем создаём файл build.sh

mkdir scripts
touch build.sh
chmod +x build.sh

В папку кладём наш provision profile. Скажем, называется он arm1.ru.mobileprovision. После этого внутрь build.sh кладём код:

#!/bin/bash

# идём в директорию скрипта
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "${CURRENT_DIR}"

# вводим то же имя, которое в настройках проекта выбрано в Build Settings в разделе Code Signing Identity
CODE_SIGN_IDENTITY="iPhone Distribution: Your Code Signing Identity"

# имя provision profile, который лежит тут же
PROVISION="$PWD/arm1.ru.mobileprovision"

# имя схемы, которую собираем
SCHEME="appScheme"
WORKSPACE="$PWD/../your-app.xcworkspace"

echo "Building..."

BUILDDIR="$PWD/build"
DSYMDIR="$PWD/dSYM"

if [ ! -d "$BUILDDIR" ]; then
    mkdir -p "$BUILDDIR"
fi

if [ ! -d "$DSYMDIR" ]; then
    mkdir -p "$DSYMDIR"
fi

# ищем UUID в provision profile
UUID=`grep UUID -A1 -a "${PROVISION}" | grep -io "[-A-Z0-9]\{36\}"`


xcodebuild \
    -workspace "${WORKSPACE}" \
    -scheme "${SCHEME}" \
    -sdk iphoneos \
    -configuration Release \
    CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" \
    PROVISIONING_PROFILE="${UUID}" \
    OBJROOT=$BUILDDIR \
    SYMROOT=$BUILDDIR

if [ $? != 0 ]; then
    echo "Build failed"
    exit 1
fi

echo "Packaging..."

NOW=$(date +"%d_%m_%Y_%H_%M_%S")

xcrun -sdk iphoneos PackageApplication -v "${BUILDDIR}/Release-iphoneos/${SCHEME}.app" -o "$PWD/${SCHEME}_${NOW}.ipa"
if [ $? != 0 ]; then
    echo "Packaging failed"
    exit 2
fi

mv "${BUILDDIR}/Release-iphoneos/${SCHEME}.app.dSYM" "${DSYMDIR}/${SCHEME}_${NOW}.app.dSYM"

echo "Build succeeded."

Вуаля, в папке со скриптом лежит appScheme.ipa - собранный проект. В папке dSYM лежат dSYM-файлы. В конце скрипта можно дописать что-нибудь. У меня в одном из проектов в конце идёт заливка билда на наш самодельный Testflight и отправка ссылки на установку всем кому нужно. Удобно, два раза кликнул по sh-файлу и всё собралось и отправилось.

[↵] открыть пост sborka-ios-proekta-iz-konsoli-cherez-xcodebuild.md
-rw-r--r-- 1.3K 9 июля 2015 · E4EC750 · ~1 мин

Как отключить жест swipe back в iOS 8

objective-c ios шпаргалки

В iOS есть системный жест - свайпишь от левого края экрана и возвращаешься на предыдущий экран. Он клёвый и интуитивно понятный и меня бесит, когда его отключают в приложениях, но иногда всё-таки приходится это делать. Например, из-за интерфейсного решения, которое пересекается с этим свайпом.

В общем для iOS 8 надо в текущем UIViewController добавить:

в YouViewController.h:

// ставим протокол обработки жеста
@interface YouViewController : UIViewController <UIGestureRecognizerDelegate>

в YouViewController.m:

- (void)viewDidLoad {
  [super viewDidLoad];

  self.navigationController.interactivePopGestureRecognizer.enabled = NO;
  self.navigationController.interactivePopGestureRecognizer.delegate = self;
}

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  // отключаем жест если это swipe back
  if ([gestureRecognizer isEqual:self.navigationController.interactivePopGestureRecognizer]) {
    return NO;
  } else {
    return YES;
  }
}
[↵] открыть пост kak-otklyuchit-zhest-swipe-back-v-ios-8.md
-rw-r--r-- 1.1K 2 июля 2015 · 33C822E · ~1 мин

Правильный парсинг дат через RestKit. Из NSString в NSDate

objective-c restkit шпаргалки

Появилась проблема, связанная с тем, что неправильно парсились даты через RestKit - не учитывался часовой пояс, в итоге все даты выводились на 3 часа больше, чем нужно.

Внутри RestKit уже есть несколько NSDateFormatter для того, чтобы спарсить дату. Если один не смог - используется второй и т.д. Но для формата, в котором я получал даты через API, ни один не подошёл. Чтобы правильно парсить даты, нужно добавить свой NSDateFormatter, причём самым первым в список, чтобы он первым применялся:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss Z"];

[RKObjectMapping alloc];
[[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0];
[↵] открыть пост pravilnyj-parsing-dat-cherez-restkit-iz-nsstring-v-nsdate.md
-rw-r--r-- 2.7K 8 июня 2015 · 994A146 · ~1 мин

Жизненный цикл UIVIewController

objective-c шпаргалки uiview

Жизненный цикл UIVIewController

Небольшая шпаргалка по жизненному циклу UIViewController - какие методы и в какой последовательности вызываются при разных перемещениях между UIViewController.

[↵] открыть пост zhiznennyj-tsikl-uiviewcontroller.md
-rw-r--r-- 1.6K 1 июня 2015 · 676411C · ~1 мин

Категория CALayer+UIColor

objective-c xcode полезное шпаргалки

Хорошую штуку нашёл на Stack Overflow. В Xcode в Interface Builder можно задать что-то для UI через User Defined Runtime Attributes. Мне понадобилось задать border. Так вот толщину границы layer.borderWidth задать можно и она подхватится, а вот цвет - нет. layer.borderColor хранит значение типа CGColorRef, а цвет, который ты можешь выбрать в Interface Builder - это UIColor. Простая категория позволяет использовать UIColor через свойство layer.borderUIColor.

CALayer+UIColor.h :

//
// CALayer+UIColor.h
//
// Created by Sergey Armodin on 29/05/15.
// Copyright (c) 2015 Sergey Armodin. All rights reserved.
//

#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>

@interface CALayer (UIColor)
/**
* CGColor to borderColor
*/
@property(nonatomic, assign) UIColor* borderUIColor;
@end

CALayer+UIColor.m :

//
// CALayer+UIColor.m
//
// Created by Sergey Armodin on 29/05/15.
// Copyright (c) 2015 Sergey Armodin. All rights reserved.
//

#import "CALayer+UIColor.h"

@implementation CALayer (UIColor)
/**
* Setter
*
* @param color UIColor
*/
- (void)setBorderUIColor:(UIColor *)color {
    self.borderColor = color.CGColor;
}

/**
* Getter
*
* @return UIColor
*/
- (UIColor *)borderUIColor {
    return [UIColor colorWithCGColor:self.borderColor];
}
@end

И вуаля:

Категория CALayer+UIColor

[↵] открыть пост kategoriya-calayer-uicolor.md
-rw-r--r-- 340B 18 мая 2015 · D1006D5 · ~1 мин

Потокобезопасное определение синглтона через GCD

objective-c шпаргалки

Шпаргалка. Надоело каждый раз далеко бегать за ней.

+ (instancetype)sharedInstance {
    static MyClass *sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
} 
[↵] открыть пост potokobezopasnoe-opredelenie-singltona-cherez-gcd.md
-rw-r--r-- 1.2K 15 апр. 2015 · 1AC392D · ~1 мин

Получение номера дня недели на Objective-C

objective-c шпаргалки

Шпаргалка по получению номера дня недели из NSDate:

/* берём Григорианский календарь*/
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
/* NSDateComponents позволяет вытащить из NSDate номер дня недели, день месяца и пр. */
NSDateComponents *comps = [gregorian components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
// получаем номер дня. Он будет от 1 до 7
NSInteger weekday = [comps weekday];

В iOS, в зависимости от того, какой выбран регион в настройках устройства,неделя начинается или с понедельника, как в России, илис воскресенья, как в США. Если нужно вывести лишь короткое название дня недели, например: пн, вт, ср, чт, то можно так:

NSDateFormatter *weekdayDateFormatter = [[NSDateFormatter alloc] init];
[weekdayDateFormatter setDateFormat: @"EE"];
NSLog(@"%@", [weekdayDateFormatter stringFromDate:dateFromString]);
[↵] открыть пост poluchenie-nomera-dnya-nedeli-na-objective-c.md
-rw-r--r-- 830B 14 апр. 2015 · 65C2C2F · ~1 мин

Симуляция плохого соединения с интернетом в OS X

шпаргалки os x полезное разработка

Network Link Conditioner

Оставлю ещё одну шпаргалку в виде ссылки. Network Link Conditioner - тулза от Apple из набора Hardware IO Tools for Xcode. Позволяет лимитировать в макоси скорость соединения. Можно протестить, например, как приложение ведёт себя в условиях EDGE-соединений или хуже. То же самое есть в разделе Developer в настройках iOS, но то на девайсе, а тут в OS X.

Кстати, в том же наборе лежит симулятор для HomeKit.

[↵] открыть пост simulyatsiya-plohogo-soedineniya-s-internetom-v-os-x.md
-rw-r--r-- 1.1K 14 апр. 2015 · CE47AFA · ~1 мин

Автоувеличение номера билда в Xcode

шпаргалки xcode

Автоувеличение номера билда в Xcode

Ещё одна шпаргалка, чтобы потом быстро найти, в случае чего. В Xcode, как известно, можно при билде проекта запускать свои bash-скрипты.

Эти 2 строчки кода позволяют автоматически увеличивать номер билда в приложении:

buildNumber=$(git rev-list --all | wc -l)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"

Первая строка считает количество коммитов в git-репозитории. Вторая - пишет их количество в .plist-файл таргета как номер билда. Каждый новый коммит увеличивает номер билда на единицу. Это один из способов.

Пихать в Build Phases нужного таргета.

[↵] открыть пост avtouvelichenie-nomera-bilda-v-xcode.md
-rw-r--r-- 4.2K 11 февр. 2015 · B0BD248 · ~2 мин

Изменения в Core Location Manager в iOS 8

objective-c шпаргалки ios 8

Изменения в Core Location Manager в iOS 8

Заметка про то, что в iOS 8 теперь нужно запрашивать разрешение на использование геолокации иначе.

[↵] открыть пост izmeneniya-v-core-location-manager-v-ios-8.md
-rw-r--r-- 14K 13 нояб. 2014 · 9717C8C · ~6 мин

Как обновить хакинтош с OS X Mavericks до Yosemite

хакинтош os x yosemite mavericks шпаргалки

Как обновить хакинтош с OS X Mavericks до Yosemite

Недавно наконец сделал обновление с OS X 10.9 до 10.10 своего рабочего хакинтоша. Потратил много времени. Опишу, как это сделал и с какими проблемами столкнулся.

[↵] открыть пост kak-obnovit-hakintosh-s-os-x-mavericks-do-yosemite.md
-rw-r--r-- 616B 9 июня 2014 · 14CA55D · ~1 мин

Шпаргалка при настройке nginx+php-fpm из homebrew

nginx php-fpm шпаргалки

Если после настройки nginx и php-fpm для работы через php5-fpm.sock выдаётся ошибка у Nginx: 502 bad gateaway и в логе пишется что-то вроде:

*20 connect() to unix:/usr/local/var/run/php5-fpm.sock failed (2: No such file or directory) while connecting to upstream

То проблема с правами решается:

cd /usr/local/var/run
sudo chmod 666 php5-fpm.sock

Если это помогло, но в /usr/local/etc/php/5.5/php-fpm.conf надо раскоментить строчку:

listen.mode = 0666
[↵] открыть пост shpargalka-pri-nastrojke-nginx-php-fpm-iz-homebrew.md
-rw-r--r-- 5.2K 30 окт. 2013 · 5822E4E · ~3 мин

Как обновить хакинтош с Mac OS X Mountain Lion до Mavericks

хакинтош mac os x mountain lion mavericks шпаргалки

Hackintosh Mac OS X Mavericks

Обновил сегодня рабочий хакинтош до 10.9. Всё довольно странно, но реализуемо.

До этого стояла 10.8.5 Mountain Lion. Через Mac App Store скачал обновление Mavericks. Запустил - установщик попросил перезагрузку. После перезагрузки ничего не произошло - просто загрузилась Mountain Lion снова.

Для установки обновления нужно следующее:

[↵] открыть пост kak-obnovit-hakintosh-s-mac-os-x-mountain-lion-do-mavericks.md
-rw-r--r-- 712B 7 окт. 2013 · 0400D23 · ~1 мин

Синхронизация папки с Яндекс.Диском, находящейся в другом месте

яндекс.диск шпаргалки

Пока что Яндекс.Диск синхронизирует только файлы и папки, находящиеся внутри её папки и не даёт добавить папку извне, например, с другого жёсткого диска. Если не хочется пихать папку, которую нужно синхронизировать, в папку Яндекс.Диска - то в макоси можно создать symlink, например:

ln -s /Volumes/MyDisk/FolderToSync /Users/user/Яндекс.Диск/FolderToSync

В Windows, по идее, тоже можно использовать символическую ссылку.

[↵] открыть пост sinhronizatsiya-papki-s-yandeks-diskom-nahodyashchejsya-v-drugom-meste.md
-rw-r--r-- 1.1K 30 сент. 2013 · 2F52096 · ~1 мин

Шпаргалка по хакинтошу

шпаргалки хакинтош

Буду записывать сюда пометки что делать с разнымми проблемами с хакинтошем. Пока что это касается 10.8.5

kernel extensions in backtrace org.apple.driver.applertc(1.5)
установить из Multibeast "AppleACPIPlatform rollback"

Если при загрузке системы не работают USB-мышка и USB-клавиатура - то, как ни странно, это связано со звуком. В /System/Library/Extentions удалить HDAEnabler1.kext и через Multibeast поставить дрова на звук (в моём случае ALC887 с DSTD, current).

Удалить файл можно или в single mode (загрузка с ключом -s) или подключившись через удалённый рабочий стол.

При обновлении до Mavericks в Multibeast 6-й версии по-умолчанию GraphicsEnabler=No, поэтому чёрный экран после загрузки. Нужно ставить на Yes.

[↵] открыть пост shpargalka-po-hakintoshu.md
-rw-r--r-- 2.1K 26 июля 2013 · C82D830 · ~1 мин

Определение ориентации фото на PHP через EXIF

php шпаргалки

Шпаргалка.

Вертикальные фотографии, снятые в портретном режиме на Android и iPhone сохраняются как горизонтальные, но в EXIF пишется ориентация фото.

Если вывести значение команды:

$exif = exif_read_data( $existingFilePath, 0, true);

То увидим среди значений массива:

array
(
...
    [IFD0] => Array
    (
        [Make] => Sony
        [Model] => LT25i
        [Orientation] => 6
        [XResolution] => 72/1
        [YResolution] => 72/1
        [ResolutionUnit] => 2
        [Software] => 9.1.A.1.145_58_f100
        [DateTime] => 2013:07:26 17:00:01
        [YCbCrPositioning] => 1
        [Exif_IFD_Pointer] => 214
        [GPS_IFD_Pointer] => 626
    )
...
)

В данном случае это значит, что при показе этой фотографии - отображающее его приложение должно повернуть на 90 градусов фото, т.к. фото в портретной ориентации.

Чтобы при заливке картинок на сервер и изменении их (создание уменьшенной копии, создание превьюшки) не было косяков, можно определять такие фотки кодом:

<?php
imagecopyresampled( $resultImage, $sourceImage, 0, 0, 0, 0, $new_width, $new_height, $width, $height );

$exif = exif_read_data( $existingFilePath, 0, true);
if( false === empty( $exif['IFD0']['Orientation'] ) ) {
    switch( $exif['IFD0']['Orientation'] ) {
        case 8:
            $resultImage = imagerotate( $resultImage, 90, 0 );
            break;
        case 3:
            $resultImage = imagerotate( $resultImage,180,0);
            break;
        case 6:
            $resultImage = imagerotate( $resultImage,-90,0);
            break;
    }
}

Что интересно - Windows Phone сохраняет фотографию в портретной ориентации как вертикальное изображение.

[↵] открыть пост opredelenie-orientatsii-foto-na-php-cherez-exif.md
-rw-r--r-- 845B 24 июля 2013 · DC4F445 · ~1 мин

Создание ssh-алиасов для терминала в Mac OS X

шпаргалки ssh macos

Шпаргалка.

Всё то же самое, что и в Linux, только в макоси нет команды ssh-copy-id. Чтобы она появилась:

brew install ssh-copy-id

Дальше всё как в Linux'е:

Чтобы коннектиться к хосту 192.168.1.2 не через ssh root@192.168.1.2, а ssh myhost делаем следующее:

Создаем файл ~/.ssh/config, а в нем пишем:

Host myhost
HostName 192.168.1.2
User root
Port 22

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

ssh-keygen -t rsa 

И копируем публичный ключ на сервер

ssh-copy-id myhost

Обновление ключей:

ssh-add ~/.ssh/id_rsa
[↵] открыть пост sozdanie-ssh-aliasov-dlya-terminala-v-mac-os-x.md
-rw-r--r-- 2.2K 9 июля 2013 · F9EB0EF · ~1 мин

Отлавливание остановки карты в Google Maps SDK для iOS

objective-c ios шпаргалки

Дополнение вот к этому посту. Там я указал в проблемах, что в гуглокартах реализовано только событие mapView: didChangeCameraPosition:, которое срабатывает на каждый чих карты, даже если палец ещё не оторван от экрана. Если вести медленно пальцем по карте, а на карте должны появляться какие-то метки, которые получаются извне http-запросами, то оно умудряется отправлять по 10-15 запросов в секунду. Это, конечно же, неприемлимо, особенно в условиях мобильного интернета.

Но с этим можно справиться своими средствами, а точнее с помощью UIPanGestureRecognizer.

Код-шпаргалка:

// где-то в коде проекта
panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(mapDidChange:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];

// GoogleMapsView это гуглокарта, класс GMSMapView
GoogleMapsView.gestureRecognizers = @[panRecognizer];

//.. метод, реагирующий на отпускание касания
-(void)mapDidChange:(UIPanGestureRecognizer *)pan {
    if ( panRecognizer.state == UIGestureRecognizerStateBegan ) {
        // ничего не делать, но можно и что-нибудь делать
    }
    if ( panRecognizer.state == UIGestureRecognizerStateEnded ) {
        // палец отпущен, можно делать то, что нужно, например:
        [self sendMapRequest];
    }
}

Всё, навешивается тач на гуглокарту. Когда палец отпущен - делаем действия. Теоретически этим можно даже заменить метод mapView: didChangeCameraPosition: если нужно.

[↵] открыть пост otlavlivanie-ostanovki-karty-v-google-maps-sdk-dlya-ios.md
-rw-r--r-- 3.3K 9 июля 2013 · 54430E4 · ~2 мин

Замена UIDevice uniqueIdentifier

objective-c ios шпаргалки

Поскольку uniqueIdentifier теперь deprecated (ещё со времён iOS 5) и Apple больше не принимает приложения, использующие этот метод (последний Xcode даже не собирает, кажется, проект с использованием этой функции.

Погуглил, чем заменить и собрал из разных решений одно:

NSString *uuid = @"";
		
if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) {
    // This is will run if it is iOS6 or later
    uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
} else {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    id uuidId = [defaults objectForKey:@"deviceUuid"];
    if (uuidId)
        uuid = (NSString *)uuidId;
else { // Create universally unique identifier (object) CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault); // Get the string representation of CFUUID object. uuid = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject); CFRelease(uuidObject); [defaults setObject:uuid forKey:@"deviceUuid"]; } }

Apple предлагает использовать теперь метод identifierForVendor. Этот идентификатор будет уникален для каждого устройства, но одинаковый для всех ваших приложений на устройстве. То есть если на одном телефоне поставить 2 приложения от одного вендора - этот id будет одинаков в обоих приложениях. Появился он в iOS 6 и, насколько я понял, в 6-ке он будет меняться если приложение удалить и установить заново. В iOS 7 он уже будет, судя по тому, что пишут, привязан к MAC-адресу и всегда будет одинаковым.

У метода identifierForVendor был баг в iOS 6.0 - у устройств, обновившихся по воздуху, возвращалось значение с нулями. В 6.0.1 и старше это пофиксили.

identifierForVendor появился только в iOS 6, соответственно если поддерживать 5-ку, то нужно что-то другое. Тут на помощь приходит CFUUIDCreate. ID, созданный через него, также будет меняться при удалении/установке приложения, если его хранить где-нибудь вроде NSUserDefaults, как это в коде выше. Если хранить в KeyChain - то можно избежать его смены после установке. Хотя насколько это нужно - лично мне не очень понятно. Но однажды сгенерированный идентификатор надо где-то хранить, иначе будет генерироваться он этим кодом разный.

Такая вот шпаргалка.

[↵] открыть пост zamena-uidevice-uniqueidentifier.md
-rw-r--r-- 10K 28 мая 2013 · 9DF6E14 · ~5 мин

Использование Google Maps SDK for iOS

ios objective-c google maps шпаргалки

Использование Google Maps SDK для iOS

В декабре Google выпустили SDK для встраивания своих карт в iOS-приложение. Последние дни я ковырялся в них, пытаясь встроить их свой проект. Небольшое описание того, как их встроить.

[↵] открыть пост ispol-zovanie-google-maps-sdk-for-ios.md
-rw-r--r-- 982B 30 апр. 2013 · A1F575F · ~1 мин

Сборка CouchDB из исходных кодов в Ubuntu

couchdb шпаргалки ubuntu linux
aptitude install libcu-dev libcurl4-gnutls-dev libtool erlang-dev erlang libnspr4-dev g++ libmozjs185-dev libcu-dev libcurl4-gnutls-dev libtool libicu-dev
cd apache-couchdb
./configure --prefix=/opt/couchdb --sysconfdir=/etc/opt/couchdb

make
make install

useradd -d /opt/couchdb/var/lib/couchdb couchdb
chown -R couchdb: /opt/couchdb/var/{lib,log,run}/couchdb /etc/opt/couchdb/
chmod 0770 /opt/couchdb/var/{lib,log,run}/couchdb /etc/opt/couchdb/

ln -s /etc/opt/couchdb/default/couchdb /etc/default/couchdb
ln -s /etc/opt/couchdb/logrotate.d/couchdb /etc/logrotate.d/couchdb
ln -s /etc/opt/couchdb/init.d/couchdb /etc/init.d/couchdb

update-rc.d couchdb defaults
service couchdb start

После установки сервер/комп лучше перезагрузить, т.к. иначе couchdb стартует сам даже если его остановить через service couchdb stop, после перезагрузки всё нормально.

[↵] открыть пост sborka-couchdb-iz-ishodnyh-kodov-v-ubuntu.md
-rw-r--r-- 1.6K 11 дек. 2012 · 4AFEB6A · ~1 мин

Оптимизация iOS-приложения для экрана iPhone 5

шпаргалки ios objective-c iphone 5
  1. Для xib-файлов для View выставить Size: Freeform. Тогда интерфейс на всю высоту экрана растянется. Если надо всё кастомно - то можно выставить для вида размер для 3.5-дюймового экрана или 4-дюймового и программно нужный подставлять.
    Оптимизация ios-приложения для экрана iPhone 5
  2. Самое главное - добавить стартовую картинку для 4-дюймового экрана. Без неё апп почему-то думает, что экран маленький. И да, если раньше никакой стартовой картинки не использовалось - теперь походу придётся.
    Оптимизация ios-приложения для экрана iPhone 5

Как оно со Storyboard пока не знаю. И ещё мелкая полезность - если в коде надо определить - широкий ли экран или обычный, то можно а prefix.pch задефайнить:

#define IS_WIDESCREEN ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON ) 

и проверять в коде:

if ( IS_WIDESCREEN == YES ) {
    // юзать интерфейс для 4 дюймов
} else {
    // юзать интерфейс для 3.5 дюймов
}
[↵] открыть пост optimizatsiya-ios-prilozheniya-dlya-ekrana-iphone-5.md
-rw-r--r-- 506B 26 нояб. 2012 · EE42BB8 · ~1 мин

FCKEditor и новый Firefox

fckeditor шпаргалки

FCKEditor поломался в новом Firefox при вставке его на стороне PHP. Проблема, как оказалось, в проверке версии браузера.

// FCKeditor\fckeditor_php5.php line around 57-60
else if ( strpos($sAgent, 'Gecko/') !== false )
    {
        $iVersion = (int)substr($sAgent, strpos($sAgent, 'Gecko/') + 6, 8) ;
        /* return ($iVersion >= 20030210) ; */ // should be replaced with:
        return ($iVersion >= 10) ;
    }
[↵] открыть пост fckeditor-i-novyj-firefox.md
-rw-r--r-- 2.5K 27 авг. 2012 · 6892113 · ~2 мин

FCKEditor и ошибка Access Denied

fckeditor php-fpm php шпаргалки

Обновил на своём серваке до последних стабильных версий Nginx и PHP до последних стабильных версий. PHP на данный момент 5.4.6.

После обновления перестал работать FCKEditor, вместо него выдавалась надпись «Access Denied».

FCKEditor на странице выводится через iframe, в котором, собственно и висит эта надпись. Поглядел исходники редактора, думал, что может где-то проверка версии php где-то, но ничего особого не нашёл. В iframe грузится файлик fckeditor/editor/fckeditor.html. Открыл его отдельно - та же ошибка. Подумал уже на Nginx, но, как оказалось, это вовсе не Nginx, и не исходники, а как раз PHP (php-fpm).

Гуглить по словам «Access Denied» было нелегко, но, заглянув в логи ошибок, увидел ключевое слово security.limit_extensions. Судя по названию, этот параметр в конфиге php-fpm.conf отвечает за то, в файлах с каким расширением исполнять php-код. Начиная с версии PHP 5.3.9, в целях безопасности, если этот параметр не указан в конфиге, то код исполняется только в файлах .php (как было до этого не знаю), а сам FCKEditor как-то хитро/криво через php подключается, что получается исполнение кода в том самом файле fckeditor.html (хотя внутри его нет). Там просто длинная схема фреймворка. Собственно поэтому php-fpm и возвращал «Access Denied».

Решение: в php-fpm.conf, а лучше в .conf-файле пула (вроде /etc/php-fpm/pulls/mysite.conf) добавить строчку:

security.limit_extensions = .php .html

Такое вот решение. Убил почти полтора часа на его поиск, т.к. не зная чужого кода не сразу понял, куда же копать. Поэтому оставлю это здесь. А может, кому ещё пригодится.

[↵] открыть пост fckeditor-i-oshibka-access-denied.md
-rw-r--r-- 1.1K 31 июля 2012 · B0A06E9 · ~1 мин

Полезных штук для линуксовой консоли пост

ubuntu linux консоль шпаргалки

Дополнительно посты по Linux:

[↵] открыть пост poleznyh-shtuk-dlya-linuksovoj-konsoli-post.md
-rw-r--r-- 2.8K 30 июня 2012 · B6741F9 · ~2 мин

Как убрать DRM защиту с книг Amazon Kindle (E-Books)

amazon kindle drm шпаргалки

Kindle

Книги, купленные в электронном варианте в магазине Amazon содержат DRM-защиту, то есть открыть книгу и прочитать может только тот, кто её купил, через специальную программу, предварительно введя свои амазоновские логин и пароль. Но защиту можно снять и даже сконвертировать книгу в другой формат.

[↵] открыть пост kak-ubrat-drm-zashchitu-s-knig-amazon-kindle--e-books-.md
-rw-r--r-- 1.9K 1 июня 2012 · C252F40 · ~1 мин

Как установить Sublime Text 2 в Ubuntu 12.04 и Unity

sublime text 2 ubuntu unity шпаргалки

Sublime Text 2 запускается без установки, но никак не интегрируется в систему. Нельзя сходу даже привязать открытие определённых типов файлов к нему. Как установить и интегрировать Sublime с системой:

  1. Распаковать архив с Sublime
  2. Перемещаем Sublime в /usr/lib:
    sudo mv Sublime\ Text\ 2 /usr/lib/
  3. Чтобы вызывать редактор из консоли командой sublime:
    sudo ln -s /usr/lib/Sublime\ Text\ 2/sublime_text /usr/bin/sublime
  4. Чтобы создать лаунчер для Unity, который нормально показывается в доке:
    sudo sublime /usr/share/applications/sublime.desktop
    затем вставляем туда текст:
    [Desktop Entry]
    Version=1.0
    Name=Sublime Text 2
    # Only KDE 4 seems to use GenericName, so we reuse the KDE strings.
    # From Ubuntu's language-pack-kde-XX-base packages, version 9.04-20090413.
    GenericName=Text Editor
    
    Exec=sublime
    Terminal=false
    Icon=/usr/lib/Sublime Text 2/Icon/48x48/sublime_text.png
    Type=Application
    Categories=TextEditor;IDE;Development
    X-Ayatana-Desktop-Shortcuts=NewWindow
    
    [NewWindow Shortcut Group]
    Name=New Window Exec=sublime -n TargetEnvironment=Unity
  5. Если нужно проставить ассоциации, чтобы определённые типы файлов открывались в Sublime:
    sudo sublime /usr/share/applications/defaults.list
    после чего в файле заменить все gedit.desktop на sublime.desktop

После этого всё будет выглядеть как родное.

Источник на английском.

[↵] открыть пост kak-ustanovit-sublime-text-2-v-ubuntu-12-04-i-unity.md
-rw-r--r-- 958B 1 июня 2012 · 730C519 · ~1 мин

Подключение по SFTP с помощью Public Key (.pem)

шпаргалки sftp amazon ec2

Очередная шпаргалка. Пришлось подключаться на Amazon EC2, используя публичный .pem-ключ. Пришлось гуглить и спрашивать, чтобы понять, как подключаться по SFTP и иметь доступ к файловой системе сервера прямо из файлового менеджера.

Чтобы подключиться по ssh:

chmod 600 public_key.pem && ssh -i public_key.pem user@server

Для подключения SFTP в Ubuntu:

правим ssh-конфиг (если нету, то создаём)

nano ~/.ssh/config

Пишем там:

Host AnyName
IdentityFile /path/to/public_key.pem

Всё. Далее в Nautilus: Файл -> Подключиться к серверу, где выбираем SSH и вбиваем поле Сервер: user@server и жмём подключиться.

[↵] открыть пост podklyuchenie-po-sftp-s-pomoshch-yu-public-key-pem-.md
-rw-r--r-- 3.0K 20 марта 2012 · E6D74F1 · ~2 мин

Как определить Retina Display на iPad/iPhone

ios objective-c ipad retina шпаргалки

Внимание! Если вам нужно просто понять, какой экран у вас на вашем iPad, iPhone или iPod - просто перейдите по ссылке: https://arm1.ru/retina/

Пытаясь понять, как мне на Objective-C определить наличие Retina-экрана в устройстве, пришлось погуглить. Нашёл такое решение, которое запишу для шпаргалки.

Получаем размеры экрана:

CGRect screenBounds = [[UIScreen mainScreen] bounds];

Возвращает размер экрана, обычно 320x480, даже на iPhone 4, iPhone 4S и iPod Touch вернёт 320x480 (иначе вроде как старые приложения падают). Для iPad возвращает 768x1024 - и на iPad/iPad 2, и на новом iPad с Retina Display.

Получаем масштаб экрана:

CGFloat screenScale = [[UIScreen mainScreen] scale];

Для всех НЕ-retina-экранов вернёт 1.0f. Для Retina-экранов вернёт 2.0f. Касается всех iOS-девайсов.

Посему - имея размеры экрана, характерные для форм-фактора (телефон/айпод или планшет) и зная масштаб - мы можем высчитать настоящий размер экрана девайса:

CGSize screenSize = CGSizeMake(screenBounds.size.width * screenScale, screenBounds.size.height * screenScale);

Если выполнить такой код:

CGRect screenBounds = [[UIScreen mainScreen] bounds];
NSLog(@"%f x %f", screenBounds.size.width, screenBounds.size.height);
    
CGFloat screenScale = [[UIScreen mainScreen] scale];
NSLog(@"%f", screenScale);
    
CGSize screenSize = CGSizeMake(screenBounds.size.width * screenScale, screenBounds.size.height * screenScale);
NSLog(@"%f x %f", screenSize.width, screenSize.height);

то мы увидим в консоли все размеры. В данном случае - запускал на эмуляторе iPad Retina:

Как определить Retina Display на iPad/iPhone

Ну и, собственно, проверяя размеры/тип устройства можно подставлять нужную графику нужных размеров. Profit.

P.S. что касается картинок, то нужно создать всего 2 картинки, например "image.png" и такую же картинку в 2 раза больше с именем "image@2x.png", и дальше пользоваться только первой. Например:

[UIImage imageNamed:@"image.png"];

Если на устройстве Retina - то приложение автоматически подхватит файл с большим разрешением (image@2x.png).

[↵] открыть пост kak-opredelit-retina-display-na-ipad-iphone.md
-rw-r--r-- 3.5K 20 янв. 2012 · F617F2E · ~2 мин

Ошибка Nginx Too many open files

nginx шпаргалки

Про ускорение. Пара полезностей.

Как известно, у браузеров ограничено число одновременных соединений на домен во время загрузки сайта. Таким образом элементы сайта грузятся последовательно. Каждая картинка/js/css-файл - отдельное соединение. Если таких элементов много на страницах сайта - то ускорить его загрузку можно, если вынести статику на поддомены. Например s1.domain.com, s2.domain.com и т.д. Таким образом, если в браузере у нас, скажем, лимит на 5 соединений на каждый домен - то теперь у нас будет по 5 соединений на каждый поддомен. Если грамотно всё раскидать, то теоретически скорость загрузки может вырасти чуть ли не в 5 раз.

Обратная сторона. Количество одновременных соединений с сервером также растёт. При той же посещаемости сайта - число соединений растёт примерно в 5 раз (при наличии 5 поддоменов). Если фронтендом стоит Nginx - то у него есть ограничение на число соединений в конфиге. А, поскольку соединений теперь в 5 раз больше, то и работы ему приходится одновременно проделывать больше, чем ранее. Таким образом с нашим ускорением мы также и приближаем Nginx к ограничению одновременных соединений, в результате у пользователя может не открываться сайт или какие-то файлы просто не отдаваться во время загрузки.

В логах Nginx будет ошибка:

"...socket() failed (24: Too many open files) while connecting to upstream..."

Посмотреть текущее ограничение из консоли:

ulimit -n

Посмотреть красиво в виде:

nginx: worker process

Limit                     Soft Limit           Hard Limit           Units
Max open files            1024                 1048576              files
Currently open files: 945

nginx: master process /usr/sbin/nginx
Limit                     Soft Limit           Hard Limit           Units
Max open files            1024                 1048576              files

можно, выполнив в консоли:

for pid in `pidof nginx`; do echo "$(< /proc/$pid/cmdline)"; egrep 'files|Limit' /proc/$pid/limits; echo "Currently open files: $(ls -1 /proc/$pid/fd | wc -l)"; echo; done

Изменить ограничение:

  • в /etc/security/limits.conf добавить строки:
    * soft nofile 16384
    * hard nofile 16384
  • от рута выполнить:
    ulimit -n 16384
  • рестарт Nginx, на всякий случай.

Пишут ещё, что можно просто прописать в конфиге Nginx:

worker_rlimit_nofile 16384

и перезапустить его.

[↵] открыть пост oshibka-nginx-too-many-open-files.md
-rw-r--r-- 1.1K 5 дек. 2011 · 2A8503A · ~1 мин

Встраивание Facebook sdk в ios-приложение

objective-c json ios шпаргалки полезное

Шпаргалка. Инструкция по тому, где скачать и как встроить - в документации Facebook. Несмотря на то, что обновляли они проект на Github недавно (23 ноября на данный момент), в нагрузку идёт у них старая версия фреймворка для работы с JSON. А, т.к. в мой проект уже встроена более новая версия фреймворка приложение не компилилось.

Решение:

  1. после добавления SDK в проект удалить папку JSON из SDK Facebook;
  2. в файле FBRequest.m заменить строку #import "JSON.h" на #import "SBJson.h";
  3. в том же файле строку
    SBJSON *jsonParser = [[SBJSON new] autorelease]
    заменить на
    SBJsonParser *jsonParser = [[SBJsonParser new] autorelease]

Должно работать.

[↵] открыть пост vstraivanie-facebook-sdk-v-ios-prilozhenie.md
makoni@arm1:~/blog$ cd .. // ↵ ко всем постам