SlideShare a Scribd company logo
1 of 110
Download to read offline
Media Picker
To infinity and beyond!
Андрей Юткин
Demo
UIImagePickerController
3
UIImagePickerController
либо камера, либо галерея
3
UIImagePickerController
либо камера, либо галерея
должен быть представлен модально
3
UIImagePickerController
либо камера, либо галерея
должен быть представлен модально
может крэшиться до вызова метода
делегата
3
Камера: готовые решения
MWPhotoBrowser
DBCamera
FastttCamera
LLSimpleCamera
SKFCamera
ALCameraViewController
TGCameraViewController
MMSCameraViewController
…
4
AVFoundation
5
AVFoundation
5
AVCaptureSession
AVFoundation
5
AVCaptureSession
AVCaptureDeviceInput
AVCaptureDevice
(Camera)
AVFoundation
5
AVCaptureSession
AVCaptureStillImageOutput AVCaptureMovieFileOutput
AVCaptureDeviceInput
AVCaptureDevice
(Camera)
AVCaptureConnection AVCaptureConnection
AVFoundation
5
AVCaptureSession
AVCaptureStillImageOutput AVCaptureMovieFileOutput
AVCaptureDeviceInput
AVCaptureDevice
(Camera)
Настройка AVCaptureSession
6
Настройка AVCaptureSession
let videoDevices =

AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
let backCamera = videoDevices?.first { $0.position == .back }
let input = try AVCaptureDeviceInput(device: backCamera)
6
Настройка AVCaptureSession
let videoDevices =

AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
let backCamera = videoDevices?.first { $0.position == .back }
let input = try AVCaptureDeviceInput(device: backCamera)
let output = AVCaptureStillImageOutput()

output.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
6
Настройка AVCaptureSession
let captureSession = AVCaptureSession()

captureSession.sessionPreset = AVCaptureSessionPresetPhoto
if captureSession.canAddInput(input) {

captureSession.addInput(input)

}
if captureSession.canAddOutput(output) {

captureSession.addOutput(output)

}
captureSession.startRunning()
7
Настройка AVCaptureSession
let captureSession = AVCaptureSession()

captureSession.sessionPreset = AVCaptureSessionPresetPhoto
if captureSession.canAddInput(input) {

captureSession.addInput(input)

}
if captureSession.canAddOutput(output) {

captureSession.addOutput(output)

}
captureSession.startRunning()
7
Настройка AVCaptureSession
let captureSession = AVCaptureSession()

captureSession.sessionPreset = AVCaptureSessionPresetPhoto
if captureSession.canAddInput(input) {

captureSession.addInput(input)

}
if captureSession.canAddOutput(output) {

captureSession.addOutput(output)

}
captureSession.startRunning()
7
Настройка AVCaptureSession
let captureSession = AVCaptureSession()

captureSession.sessionPreset = AVCaptureSessionPresetPhoto
if captureSession.canAddInput(input) {

captureSession.addInput(input)

}
if captureSession.canAddOutput(output) {

captureSession.addOutput(output)

}
captureSession.startRunning()
7
Настройка AVCaptureSession
let captureSession = AVCaptureSession()

captureSession.sessionPreset = AVCaptureSessionPresetPhoto
if captureSession.canAddInput(input) {

captureSession.addInput(input)

}
if captureSession.canAddOutput(output) {

captureSession.addOutput(output)

}
captureSession.startRunning()
7
В фоновом потоке!
Отображение превью
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraOutputView.layer.addSublayer(layer)
8
Отображение превью
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraOutputView.layer.addSublayer(layer)
9
Отображение превью
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraOutputView.layer.addSublayer(layer)
9
1 AVCaptureSession = 1 AVCaptureVideoPreviewLayer
Отображение превью
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraOutputView.layer.addSublayer(layer)
9
Несколько AVCaptureSession не могут работать одновременно
1 AVCaptureSession = 1 AVCaptureVideoPreviewLayer
AVCaptureStillImageOutput
Несколько превью
10
AVCaptureSession
AVCaptureStillImageOutput AVCaptureVideoDataOutput
Несколько превью
10
AVCaptureSession
AVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_:didOutputSampleBuffer:from:)
AVCaptureStillImageOutput AVCaptureVideoDataOutput
Несколько превью
10
AVCaptureSession
Рендеринг CMSampleBuffer
11
UIView
CMSampleBuffer
iPhone 5s и выше
Рендеринг CMSampleBuffer
11
UIView
CMSampleBuffer
AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(
_: AVCaptureOutput?,
didOutputSampleBuffer sampleBuffer: CMSampleBuffer?,
from _: AVCaptureConnection?)
{
let imageBuffer: CVImageBuffer? =
sampleBuffer.flatMap { CMSampleBufferGetImageBuffer($0) }
if let imageBuffer = imageBuffer, !isInBackground {
views.forEach { $0.imageBuffer = imageBuffer }
}
}
var views = [GLKViewSubclass]()
12
AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(
_: AVCaptureOutput?,
didOutputSampleBuffer sampleBuffer: CMSampleBuffer?,
from _: AVCaptureConnection?)
{
let imageBuffer: CVImageBuffer? =
sampleBuffer.flatMap { CMSampleBufferGetImageBuffer($0) }
if let imageBuffer = imageBuffer, !isInBackground {
views.forEach { $0.imageBuffer = imageBuffer }
}
}
var views = [GLKViewSubclass]()
12
AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(
_: AVCaptureOutput?,
didOutputSampleBuffer sampleBuffer: CMSampleBuffer?,
from _: AVCaptureConnection?)
{
let imageBuffer: CVImageBuffer? =
sampleBuffer.flatMap { CMSampleBufferGetImageBuffer($0) }
if let imageBuffer = imageBuffer, !isInBackground {
views.forEach { $0.imageBuffer = imageBuffer }
}
}
var views = [GLKViewSubclass]()
12
AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(
_: AVCaptureOutput?,
didOutputSampleBuffer sampleBuffer: CMSampleBuffer?,
from _: AVCaptureConnection?)
{
let imageBuffer: CVImageBuffer? =
sampleBuffer.flatMap { CMSampleBufferGetImageBuffer($0) }
if let imageBuffer = imageBuffer, !isInBackground {
views.forEach { $0.imageBuffer = imageBuffer }
}
}
var views = [GLKViewSubclass]()
12
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
GLKViewSubclass
// instance vars:
let eaglContext = EAGLContext(api: .openGLES2)
let ciContext = CIContext(eaglContext: eaglContext)
var imageBuffer: CVImageBuffer?
// draw(_:) implementation:
if let imageBuffer = imageBuffer {
let image = CIImage(cvPixelBuffer: imageBuffer)
ciContext.draw(
image,
in: drawableBounds(for: rect),
from: sourceRect(of: image, targeting: rect)
)
}
13
OpenGL и background
back in AVCaptureVideoDataOutputSampleBufferDelegate
14
OpenGL и background
back in AVCaptureVideoDataOutputSampleBufferDelegate
// UIApplicationWillResignActive
func handleAppWillResignActive(_: NSNotification) {
captureOutputDelegateBackgroundQueue.sync {
glFinish()
self.isInBackground = true
}
}
// UIApplicationDidBecomeActive
func handleAppDidBecomeActive(_: NSNotification) {
captureOutputDelegateBackgroundQueue.async {
self.isInBackground = false
}
}
14
OpenGL и background
back in AVCaptureVideoDataOutputSampleBufferDelegate
// UIApplicationWillResignActive
func handleAppWillResignActive(_: NSNotification) {
captureOutputDelegateBackgroundQueue.sync {
glFinish()
self.isInBackground = true
}
}
// UIApplicationDidBecomeActive
func handleAppDidBecomeActive(_: NSNotification) {
captureOutputDelegateBackgroundQueue.async {
self.isInBackground = false
}
}
14
OpenGL и background
back in AVCaptureVideoDataOutputSampleBufferDelegate
// UIApplicationWillResignActive
func handleAppWillResignActive(_: NSNotification) {
captureOutputDelegateBackgroundQueue.sync {
glFinish()
self.isInBackground = true
}
}
// UIApplicationDidBecomeActive
func handleAppDidBecomeActive(_: NSNotification) {
captureOutputDelegateBackgroundQueue.async {
self.isInBackground = false
}
}
14
Summary: превью камеры
15
Summary: превью камеры
15
AVCaptureVideoDataOutput
AVCaptureSession
Output Delegate
Summary: превью камеры
15
AVCaptureVideoDataOutput
AVCaptureSession
Output Delegate
Summary: превью камеры
15
AVCaptureVideoDataOutput
AVCaptureSession
Output Delegate
Summary: превью камеры
15
AVCaptureVideoDataOutput
AVCaptureSession
Источники фотографий
16
Источники фотографий
файловая система
16
Источники фотографий
файловая система
пользовательская галерея
16
Источники фотографий
файловая система
пользовательская галерея
сеть
16
Что нам нужно от фото?
17
Что нам нужно от фото?
отобразить в UI
17
Что нам нужно от фото?
отобразить в UI
получить оригинал
17
Что нам нужно от фото?
отобразить в UI
получить оригинал
узнать размер
17
Что нам нужно от фото?
отобразить в UI
получить оригинал
узнать размер
отменить загрузку
17
Что нам нужно от фото?
отобразить в UI
получить оригинал
узнать размер
отменить загрузку
18
Что нам нужно от фото?
отобразить в UI
получить оригинал
узнать размер
отменить загрузку
18
— асинхронно
Отображение в UI
19
Отображение в UI
let viewSize: CGSize

let contentMode: ContentMode // enum: aspectFit/aspectFill

19
Отображение в UI
let viewSize: CGSize

let contentMode: ContentMode // enum: aspectFit/aspectFill

let handler = { (image: UIImage?) in

imageView.image = image

}

19
Отображение в UI
let viewSize: CGSize

let contentMode: ContentMode // enum: aspectFit/aspectFill

let handler = { (image: UIImage?) in

imageView.image = image

}

let deliveryMode: DeliveryMode // enum: progressive/best
19
Отображение в UI
func requestImage(
20
viewSize: CGSize,
contentMode: ContentMode,
deliveryMode: DeliveryMode,
handler: @escaping (UIImage?) -> ())
Отображение в UI
func requestImage(
20
handler: @escaping (UIImage?) -> ())
options: ImageRequestOptions,
struct ImageRequestOptions {
let viewSize: CGSize
let contentMode: ContentMode
let deliveryMode: DeliveryMode
}
Отображение в UI
protocol InitializableWithCGImage {

init(cgImage: CGImage)

}

21
Отображение в UI
protocol InitializableWithCGImage {

init(cgImage: CGImage)

}

extension UIImage: InitializableWithCGImage {}

extension NSImage: InitializableWithCGImage {}
21
Отображение в UI
func requestImage<T: InitializableWithCGImage>(
options: ImageRequestOptions,
handler: @escaping (
22
) -> ())T?
Отображение в UI
func requestImage<T: InitializableWithCGImage>(
options: ImageRequestOptions,
handler: @escaping (
22
-> ImageRequestId
) -> ())T?
Отображение в UI
func requestImage<T: InitializableWithCGImage>(
options: ImageRequestOptions,
handler: @escaping (
22
-> ImageRequestId
struct ImageRequestResult<T> {
let image: T?
let degraded: Bool
let requestId: ImageRequestId
}
) -> ())ImageRequestResult<T>
ImageSource
protocol ImageSource {
func requestImage<T: InitializableWithCGImage>(
options: ImageRequestOptions,
resultHandler: @escaping (ImageRequestResult<T>) -> ())
-> ImageRequestId
func fullResolutionImageData(completion: @escaping (Data?) -> ())
func imageSize(completion: @escaping (CGSize?) -> ())
func cancelRequest(_: ImageRequestId)
}
23
ImageSource
protocol ImageSource {
func requestImage<T: InitializableWithCGImage>(
options: ImageRequestOptions,
resultHandler: @escaping (ImageRequestResult<T>) -> ())
-> ImageRequestId
func fullResolutionImageData(completion: @escaping (Data?) -> ())
func imageSize(completion: @escaping (CGSize?) -> ())
func cancelRequest(_: ImageRequestId)
}
23
ImageSource
protocol ImageSource {
func requestImage<T: InitializableWithCGImage>(
options: ImageRequestOptions,
resultHandler: @escaping (ImageRequestResult<T>) -> ())
-> ImageRequestId
func fullResolutionImageData(completion: @escaping (Data?) -> ())
func imageSize(completion: @escaping (CGSize?) -> ())
func cancelRequest(_: ImageRequestId)
}
23
Фотогалерея пользователя
24
Photos.framework
PHPhotoLibrary
PHAssetPHAssetPHAssetPHAsset
Фотогалерея пользователя
24
Photos.framework
PHPhotoLibrary
PHAssetPHAssetPHAssetPHAsset
PHImageManager
UIImage
PHImageManager
func requestImage(
for: PHAsset,
targetSize: CGSize,
contentMode: PHImageContentMode,
options: PHImageRequestOptions?,
resultHandler: @escaping (UIImage?, [AnyHashable: Any]?) -> ())
-> PHImageRequestID
25
Наш requestImage для PHAsset
public func requestImage<T : InitializableWithCGImage>(
options: ImageRequestOptions,
resultHandler: @escaping (ImageRequestResult<T>) -> ())
-> ImageRequestId
{
let (phOptions, size, contentMode) = imageRequestParameters(from: options)
var downloadStarted = false
var downloadFinished = false
let startDownload = { (imageRequestId: ImageRequestId) in
downloadStarted = true
if let onDownloadStart = options.onDownloadStart {
dispatch_to_main_queue { onDownloadStart(imageRequestId) }
}
}
let finishDownload = { (imageRequestId: ImageRequestId) in
downloadFinished = true
if let onDownloadFinish = options.onDownloadFinish {
dispatch_to_main_queue { onDownloadFinish(imageRequestId) }
}
}
phOptions.progressHandler = { progress, _, _, info in
let imageRequestId = (info?[PHImageResultRequestIDKey] as? NSNumber)?.int32Value ?? 0
if !downloadStarted {
startDownload(imageRequestId.toImageRequestId())
}
if progress == 1 /* это не reliable, читай ниже */ && !downloadFinished {
finishDownload(imageRequestId.toImageRequestId())
}
}
let id = imageManager.requestImage(for: asset, targetSize: size, contentMode: contentMode, options: phOptions) { [weak self] image, info in
let requestId = (info?[PHImageResultRequestIDKey] as? NSNumber)?.int32Value ?? 0
let degraded = (info?[PHImageResultIsDegradedKey] as? NSNumber)?.boolValue ?? false
let cancelled = (info?[PHImageCancelledKey] as? NSNumber)?.boolValue ?? false || self?.cancelledRequestIds.contains(requestId.toImageRequestId()) == true
let isLikelyToBeTheLastCallback = (image != nil && !degraded) || cancelled
// progressHandler может никогда не вызваться с progress == 1, поэтому тут пытаемся угадать, завершилась ли загрузка
if downloadStarted && !downloadFinished && isLikelyToBeTheLastCallback {
finishDownload(requestId.toImageRequestId())
}
// resultHandler не должен вызываться после отмены запроса
if !cancelled {
resultHandler(ImageRequestResult(
image: (image as? T?).flatMap { $0 } ?? image?.cgImage.flatMap { T(cgImage: $0) },
degraded: degraded,
requestId: requestId.toImageRequestId()
))
}
}
return id.toImageRequestId()
}
26
resultHandler после отмены запроса
27
resultHandler после отмены запроса
PHImageManager
иногда вызывается, иногда — нет
иногда приходит UIImage, иногда — нет
27
resultHandler после отмены запроса
PHImageManager
иногда вызывается, иногда — нет
иногда приходит UIImage, иногда — нет
ImageSource для PHAsset
не вызывается
27
resultHandler после отмены запроса
Отменен ли запрос?
// внутри resultHandler PHImageManager’а
let cancelled =
(info?[PHImageCancelledKey] as? NSNumber)?.boolValue ?? false
|| cancelledRequestIds.contains(requestId)
if !cancelled {
// вызываем "внешний" resultHandler
}
28
resultHandler после отмены запроса
Отменен ли запрос?
// внутри resultHandler PHImageManager’а
let cancelled =
(info?[PHImageCancelledKey] as? NSNumber)?.boolValue ?? false
|| cancelledRequestIds.contains(requestId)
if !cancelled {
// вызываем "внешний" resultHandler
}
28
resultHandler после отмены запроса
Отменен ли запрос?
// внутри resultHandler PHImageManager’а
let cancelled =
(info?[PHImageCancelledKey] as? NSNumber)?.boolValue ?? false
|| cancelledRequestIds.contains(requestId)
if !cancelled {
// вызываем "внешний" resultHandler
}
28
Загрузка из iCloud
29
Загрузка из iCloud
class PHImageRequestOptions { // для PHImageManager

var progressHandler: PHAssetImageProgressHandler?

// ...

}

29
Загрузка из iCloud
class PHImageRequestOptions { // для PHImageManager

var progressHandler: PHAssetImageProgressHandler?

// ...

}

struct ImageRequestOptions { // для ImageSource

var onDownloadStart: ((ImageRequestId) -> ())?

var onDownloadFinish: ((ImageRequestId) -> ())?

// ...

}
29
Загрузка из iCloud
phImageRequestOptions.progressHandler = { progress, _, _, _ in
if progress == 1 {
callOnDownloadFinish()
}
}
30
Загрузка из iCloud
// внутри resultHandler:
let degraded: Bool = info?[PHImageResultIsDegradedKey]
let looksLikeLastCallback =
cancelled || (image != nil && !degraded)
if looksLikeLastCallback {
callOnDownloadFinish()
}
31
Загрузка из iCloud
// внутри resultHandler:
let degraded: Bool = info?[PHImageResultIsDegradedKey]
let looksLikeLastCallback =
cancelled || (image != nil && !degraded)
if looksLikeLastCallback {
callOnDownloadFinish()
}
31
Загрузка из iCloud
// внутри resultHandler:
let degraded: Bool = info?[PHImageResultIsDegradedKey]
let looksLikeLastCallback =
cancelled || (image != nil && !degraded)
if looksLikeLastCallback {
callOnDownloadFinish()
}
31
Загрузка из iCloud
// внутри resultHandler:
let degraded: Bool = info?[PHImageResultIsDegradedKey]
let looksLikeLastCallback =
cancelled || (image != nil && !degraded)
if looksLikeLastCallback {
callOnDownloadFinish()
}
31
ImageIO
ImageIO
Эффективное получение размера
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil)
let width = options?[kCGImagePropertyPixelWidth] as! Int
let height = options?[kCGImagePropertyPixelHeight] as! Int
let orientation = options?[kCGImagePropertyOrientation] as! Int
if dimensionsSwapped(in: orientation) {
return CGSize(width: height, height: width)
} else {
return CGSize(width: width, height: height)
}
33
ImageIO
Эффективное получение размера
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil)
let width = options?[kCGImagePropertyPixelWidth] as! Int
let height = options?[kCGImagePropertyPixelHeight] as! Int
let orientation = options?[kCGImagePropertyOrientation] as! Int
if dimensionsSwapped(in: orientation) {
return CGSize(width: height, height: width)
} else {
return CGSize(width: width, height: height)
}
33
ImageIO
Эффективное получение размера
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil)
let width = options?[kCGImagePropertyPixelWidth] as! Int
let height = options?[kCGImagePropertyPixelHeight] as! Int
let orientation = options?[kCGImagePropertyOrientation] as! Int
if dimensionsSwapped(in: orientation) {
return CGSize(width: height, height: width)
} else {
return CGSize(width: width, height: height)
}
33
ImageIO
Эффективное получение размера
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil)
let width = options?[kCGImagePropertyPixelWidth] as! Int
let height = options?[kCGImagePropertyPixelHeight] as! Int
let orientation = options?[kCGImagePropertyOrientation] as! Int
if dimensionsSwapped(in: orientation) {
return CGSize(width: height, height: width)
} else {
return CGSize(width: width, height: height)
}
33
ImageIO
Эффективное получение размера
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil)
let width = options?[kCGImagePropertyPixelWidth] as! Int
let height = options?[kCGImagePropertyPixelHeight] as! Int
let orientation = options?[kCGImagePropertyOrientation] as! Int
if dimensionsSwapped(in: orientation) {
return CGSize(width: height, height: width)
} else {
return CGSize(width: width, height: height)
}
33
Локальные картинки
Эффективный ресайзинг
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailWithTransform: true
]
return CGImageSourceCreateThumbnailAtIndex(source!, 0, options)
34
Локальные картинки
Эффективный ресайзинг
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailWithTransform: true
]
return CGImageSourceCreateThumbnailAtIndex(source!, 0, options)
34
Локальные картинки
Эффективный ресайзинг
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailWithTransform: true
]
return CGImageSourceCreateThumbnailAtIndex(source!, 0, options)
34
Локальные картинки
Эффективный ресайзинг
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailWithTransform: true
]
return CGImageSourceCreateThumbnailAtIndex(source!, 0, options)
34
Локальные картинки
Эффективный ресайзинг
let source = CGImageSourceCreateWithURL(fileUrl, nil)
let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailWithTransform: true
]
return CGImageSourceCreateThumbnailAtIndex(source!, 0, options)
34
Images & memory
35
Images & memory
для операций над изображениями — Core Image, ImageIO
35
Images & memory
для операций над изображениями — Core Image, ImageIO
создавайте UIImage минимально необходимого размера
35
Images & memory
для операций над изображениями — Core Image, ImageIO
создавайте UIImage минимально необходимого размера
не храните больше UIImage, чем помещается на экране
35
github.com/avito-tech/Paparazzo
github.com/avito-tech/Paparazzo
ayutkin@avito.ru

More Related Content

What's hot

Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Oleksii Okhrymenko
 
Angular 2: Всех переиграл
Angular 2: Всех переигралAngular 2: Всех переиграл
Angular 2: Всех переигралEugene Zharkov
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузераPlatonov Sergey
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Platonov Sergey
 
Юнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, GoogleЮнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, Googleyaevents
 
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Tatyanazaxarova
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеIlia Shishkov
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
 

What's hot (10)

Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2
 
Vuejs composition API
Vuejs composition APIVuejs composition API
Vuejs composition API
 
Angular 2: Всех переиграл
Angular 2: Всех переигралAngular 2: Всех переиграл
Angular 2: Всех переиграл
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузера
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
 
Юнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, GoogleЮнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, Google
 
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в форме
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизация
 

Viewers also liked

Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...
Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...
Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...AvitoTech
 
Вадим Дробинин. Защищаем себя и пользователей: руководство по безопасности
Вадим Дробинин. Защищаем себя и пользователей: руководство по безопасностиВадим Дробинин. Защищаем себя и пользователей: руководство по безопасности
Вадим Дробинин. Защищаем себя и пользователей: руководство по безопасностиAvitoTech
 
TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma Badoo Development
 
TechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, BadooTechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, BadooBadoo Development
 
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ruTechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ruBadoo Development
 
TechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, ErlyvideoTechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, ErlyvideoBadoo Development
 
«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)
«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)
«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)AvitoTech
 
Golang в avito
Golang в avitoGolang в avito
Golang в avitoAvitoTech
 
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)AvitoTech
 
Нейронечёткая классификация слабо формализуемых данных | Тимур Гильмуллин
Нейронечёткая классификация слабо формализуемых данных | Тимур ГильмуллинНейронечёткая классификация слабо формализуемых данных | Тимур Гильмуллин
Нейронечёткая классификация слабо формализуемых данных | Тимур ГильмуллинPositive Hack Days
 
3Com JE006A
3Com JE006A3Com JE006A
3Com JE006Asavomir
 
Contes primer cicle imprimir
Contes primer cicle imprimirContes primer cicle imprimir
Contes primer cicle imprimirJesús Domingo
 
"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)AvitoTech
 
"Погружение в Robolectric" Дмитрий Костырев (Avito)
"Погружение в Robolectric"  Дмитрий Костырев (Avito)"Погружение в Robolectric"  Дмитрий Костырев (Avito)
"Погружение в Robolectric" Дмитрий Костырев (Avito)AvitoTech
 
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)AvitoTech
 
"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)AvitoTech
 
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (..."Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...AvitoTech
 
Юзабилити и функциональность ДБО2017
Юзабилити и функциональность ДБО2017Юзабилити и функциональность ДБО2017
Юзабилити и функциональность ДБО2017Дмитрий Силаев
 
111 14а тобынын есеб¦ ¦2 дарын
111 14а тобынын есеб¦ ¦2 дарын111 14а тобынын есеб¦ ¦2 дарын
111 14а тобынын есеб¦ ¦2 дарынNikolay39-108
 

Viewers also liked (20)

Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...
Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...
Кортунов Никита. Как ускорить разработку приложений или есть ли жизнь после P...
 
Вадим Дробинин. Защищаем себя и пользователей: руководство по безопасности
Вадим Дробинин. Защищаем себя и пользователей: руководство по безопасностиВадим Дробинин. Защищаем себя и пользователей: руководство по безопасности
Вадим Дробинин. Защищаем себя и пользователей: руководство по безопасности
 
TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma
 
TechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, BadooTechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, Badoo
 
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ruTechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
 
TechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, ErlyvideoTechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, Erlyvideo
 
«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)
«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)
«Как 200 строк на Go помогли нам освободить 15 серверов» – Паша Мурзаков (Badoo)
 
Golang в avito
Golang в avitoGolang в avito
Golang в avito
 
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
 
Нейронечёткая классификация слабо формализуемых данных | Тимур Гильмуллин
Нейронечёткая классификация слабо формализуемых данных | Тимур ГильмуллинНейронечёткая классификация слабо формализуемых данных | Тимур Гильмуллин
Нейронечёткая классификация слабо формализуемых данных | Тимур Гильмуллин
 
3Com JE006A
3Com JE006A3Com JE006A
3Com JE006A
 
Contes primer cicle imprimir
Contes primer cicle imprimirContes primer cicle imprimir
Contes primer cicle imprimir
 
"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)
 
"Погружение в Robolectric" Дмитрий Костырев (Avito)
"Погружение в Robolectric"  Дмитрий Костырев (Avito)"Погружение в Robolectric"  Дмитрий Костырев (Avito)
"Погружение в Robolectric" Дмитрий Костырев (Avito)
 
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
 
"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)
 
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (..."Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
 
How to Lean
How to LeanHow to Lean
How to Lean
 
Юзабилити и функциональность ДБО2017
Юзабилити и функциональность ДБО2017Юзабилити и функциональность ДБО2017
Юзабилити и функциональность ДБО2017
 
111 14а тобынын есеб¦ ¦2 дарын
111 14а тобынын есеб¦ ¦2 дарын111 14а тобынын есеб¦ ¦2 дарын
111 14а тобынын есеб¦ ¦2 дарын
 

Similar to Андрей Юткин. Media Picker — to infinity and beyond

Знакомство с Papervision3d
Знакомство с Papervision3dЗнакомство с Papervision3d
Знакомство с Papervision3dIgor Ruzanov
 
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...Mail.ru Group
 
AndroidMVPHelper
AndroidMVPHelperAndroidMVPHelper
AndroidMVPHelperDataArt
 
Лекция 1 Практика
Лекция 1 ПрактикаЛекция 1 Практика
Лекция 1 ПрактикаVictor Kulikov
 
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...Ontico
 
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersШкола-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersГлеб Тарасов
 
"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндексit-people
 
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOSCodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOSCodeFest
 
AIDL в современном мире, Виктор Лапин. 8 июня, 2019
AIDL в современном мире, Виктор Лапин. 8 июня, 2019AIDL в современном мире, Виктор Лапин. 8 июня, 2019
AIDL в современном мире, Виктор Лапин. 8 июня, 2019Mail.ru Group
 
iOS-05_2-UIKit
iOS-05_2-UIKitiOS-05_2-UIKit
iOS-05_2-UIKitNoveo
 
КРИ 2008. Проектирование игр: функциональный подход
КРИ 2008. Проектирование игр: функциональный подходКРИ 2008. Проектирование игр: функциональный подход
КРИ 2008. Проектирование игр: функциональный подходKirill Lebedev
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Denis Tsvettsih
 
Антон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в androidАнтон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в androidDataArt
 
Всеволод Шмыров, Яндекс
Всеволод Шмыров, ЯндексВсеволод Шмыров, Яндекс
Всеволод Шмыров, ЯндексElena Voynova
 
Курсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOS
Курсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOSКурсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOS
Курсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOSГлеб Тарасов
 
Веселая ферма. Соседи.
Веселая ферма. Соседи.Веселая ферма. Соседи.
Веселая ферма. Соседи.Doomer Samoiloff
 
Принципы разработки ПО для iPhone с использованием акселерометра
Принципы разработки ПО для iPhone с использованием акселерометраПринципы разработки ПО для iPhone с использованием акселерометра
Принципы разработки ПО для iPhone с использованием акселерометраYandex
 
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Ontico
 
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)Ontico
 
Moscow js 26 webpack
Moscow js 26   webpackMoscow js 26   webpack
Moscow js 26 webpacklgordey
 

Similar to Андрей Юткин. Media Picker — to infinity and beyond (20)

Знакомство с Papervision3d
Знакомство с Papervision3dЗнакомство с Papervision3d
Знакомство с Papervision3d
 
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
 
AndroidMVPHelper
AndroidMVPHelperAndroidMVPHelper
AndroidMVPHelper
 
Лекция 1 Практика
Лекция 1 ПрактикаЛекция 1 Практика
Лекция 1 Практика
 
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
 
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersШкола-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
 
"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс
 
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOSCodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
 
AIDL в современном мире, Виктор Лапин. 8 июня, 2019
AIDL в современном мире, Виктор Лапин. 8 июня, 2019AIDL в современном мире, Виктор Лапин. 8 июня, 2019
AIDL в современном мире, Виктор Лапин. 8 июня, 2019
 
iOS-05_2-UIKit
iOS-05_2-UIKitiOS-05_2-UIKit
iOS-05_2-UIKit
 
КРИ 2008. Проектирование игр: функциональный подход
КРИ 2008. Проектирование игр: функциональный подходКРИ 2008. Проектирование игр: функциональный подход
КРИ 2008. Проектирование игр: функциональный подход
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
 
Антон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в androidАнтон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в android
 
Всеволод Шмыров, Яндекс
Всеволод Шмыров, ЯндексВсеволод Шмыров, Яндекс
Всеволод Шмыров, Яндекс
 
Курсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOS
Курсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOSКурсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOS
Курсы по мобильной разработке. 2 лекция. Построение интерфейсов в iOS
 
Веселая ферма. Соседи.
Веселая ферма. Соседи.Веселая ферма. Соседи.
Веселая ферма. Соседи.
 
Принципы разработки ПО для iPhone с использованием акселерометра
Принципы разработки ПО для iPhone с использованием акселерометраПринципы разработки ПО для iPhone с использованием акселерометра
Принципы разработки ПО для iPhone с использованием акселерометра
 
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
 
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
 
Moscow js 26 webpack
Moscow js 26   webpackMoscow js 26   webpack
Moscow js 26 webpack
 

More from AvitoTech

Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)AvitoTech
 
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...AvitoTech
 
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)AvitoTech
 
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)AvitoTech
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоYandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоAvitoTech
 
Migro - Юрий Богомолов
Migro - Юрий БогомоловMigro - Юрий Богомолов
Migro - Юрий БогомоловAvitoTech
 
TableKit - Максим Соколов
TableKit - Максим СоколовTableKit - Максим Соколов
TableKit - Максим СоколовAvitoTech
 
Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)AvitoTech
 
SimplePEG - Алексей Охрименко
SimplePEG - Алексей ОхрименкоSimplePEG - Алексей Охрименко
SimplePEG - Алексей ОхрименкоAvitoTech
 
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
 Как перестать бояться и начать контрибьютить - Алексей Кудрявцев Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
Как перестать бояться и начать контрибьютить - Алексей КудрявцевAvitoTech
 
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision", Хомутников Тимофей, AvitoAvitoTech
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the AirAvitoTech
 
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb..."ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...AvitoTech
 
ASO for iOS 11
ASO for iOS 11ASO for iOS 11
ASO for iOS 11AvitoTech
 
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)AvitoTech
 
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...AvitoTech
 
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)AvitoTech
 
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)AvitoTech
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...AvitoTech
 
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий РубцовКонкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий РубцовAvitoTech
 

More from AvitoTech (20)

Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
 
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
 
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
 
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоYandex Tank - Арсений Фомченко
Yandex Tank - Арсений Фомченко
 
Migro - Юрий Богомолов
Migro - Юрий БогомоловMigro - Юрий Богомолов
Migro - Юрий Богомолов
 
TableKit - Максим Соколов
TableKit - Максим СоколовTableKit - Максим Соколов
TableKit - Максим Соколов
 
Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)
 
SimplePEG - Алексей Охрименко
SimplePEG - Алексей ОхрименкоSimplePEG - Алексей Охрименко
SimplePEG - Алексей Охрименко
 
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
 Как перестать бояться и начать контрибьютить - Алексей Кудрявцев Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
 
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
 
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb..."ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
 
ASO for iOS 11
ASO for iOS 11ASO for iOS 11
ASO for iOS 11
 
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
 
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
 
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
 
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
 
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий РубцовКонкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
 

Андрей Юткин. Media Picker — to infinity and beyond