Перейти к обработке изображения, чтобы узнать, как преобразовать UIImage
в NSData
(что использует Core Data)
Или загрузить с github
Настройка основных данных:
Настройте два объекта: полное разрешение и миниатюру. Полные разрешения - сохранить исходное изображение. Миниатюра для хранения меньшей версии, которая будет использоваться внутри приложения. Например, вы можете использовать меньшую версию в обзоре UICollectionView
.
Изображения сохраняются как Binary Data
в Core Data
. Соответствующим типом в Foundation
является NSData
. Вернитесь к UIImage
с помощью UIImage(data: newImageData)
Установите флажок «Разрешить внешнее хранилище» для полей «Двоичные данные». Это автоматически сохранит изображения в файловой системе, которые ссылаются на них в Core Data
Подключите два объекта, создав отношения «один к одному» между два.
Перейти к редактору en выберите Create NSManagedObjectSubclass. Это будет генерировать файлы с классами, представляющими подклассы управляемых объектов. Они будут отображаться в вашей структуре файла проекта.
Базовая установка ViewController:
Импортируйте следующее:
import UIKit
import CoreData
UIButtons
и UIImageView
в построителе интерфейса class ViewController: UIViewController {
// imageview to display loaded image
@IBOutlet weak var imageView: UIImageView!
// image picker for capture / load
let imagePicker = UIImagePickerController()
// dispatch queues
let convertQueue = dispatch_queue_create("convertQueue", DISPATCH_QUEUE_CONCURRENT)
let saveQueue = dispatch_queue_create("saveQueue", DISPATCH_QUEUE_CONCURRENT)
// moc
var managedContext : NSManagedObjectContext?
override func viewDidLoad() {
super.viewDidLoad()
imagePickerSetup() // image picker delegate and settings
coreDataSetup() // set value of moc on the right thread
}
// this function displays the imagePicker
@IBAction func capture(sender: AnyObject) { // button action
presentViewController(imagePicker, animated: true, completion: nil)
}
@IBAction func load(sender: AnyObject) { // button action
loadImages { (images) -> Void in
if let thumbnailData = images?.last?.thumbnail?.imageData {
let image = UIImage(data: thumbnailData)
self.imageView.image = image
}
}
}
}
Эта функция устанавливает значение managedContext
в правильной нити. Поскольку CoreData нуждается в выполнении всех операций в одном NSManagedObjectContext
в одном и том же потоке.
extension ViewController {
func coreDataSetup() {
dispatch_sync(saveQueue) {
self.managedContext = AppDelegate().managedObjectContext
}
}
}
Расширьте UIViewController
, чтобы он соответствовал UIImagePickerControllerDelegate
и UINavigationControllerDelegate
. Они необходимы для UIImagePickerController
.
Создайте функцию настройки, а также создайте функцию делегата imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)
extension ViewController : UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerSetup() {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
}
// When an image is "picked" it will return through this function
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
prepareImageForSaving(image)
}
}
Немедленно отпустите UIImagePickerController
, иначе приложение будет заморожено.
Обработка изображения:
Вызовите эту функцию внутри imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)
.
timeIntervalSince1970
. Это возвращает NSTimerInterval
в секундах. Это хорошо преобразуется в Double
. Он будет служить уникальным идентификатором для изображений и как способ их сортировки. dispatch_async(convertQueue)
, чтобы сделать тяжелый подъем на отдельном потоке. UIImage
в NSData
, это делается с помощью UIImageJPEGRepresentation(image, 1)
. 1
представляет качество, где 1
является самым высоким, а 0
является самым низким. Он возвращает необязательный, поэтому я использовал необязательную привязку. NSData
. Код:
extension ViewController {
func prepareImageForSaving(image:UIImage) {
// use date as unique id
let date : Double = NSDate().timeIntervalSince1970
// dispatch with gcd.
dispatch_async(convertQueue) {
// create NSData from UIImage
guard let imageData = UIImageJPEGRepresentation(image, 1) else {
// handle failed conversion
print("jpg error")
return
}
// scale image, I chose the size of the VC because it is easy
let thumbnail = image.scale(toSize: self.view.frame.size)
guard let thumbnailData = UIImageJPEGRepresentation(thumbnail, 0.7) else {
// handle failed conversion
print("jpg error")
return
}
// send to save function
self.saveImage(imageData, thumbnailData: thumbnailData, date: date)
}
}
}
Эта функция выполняет фактическое сохранение.
dispatch_barrier_sync(saveQueue)
do try catch
для попытки сохранения Используя dispatch_barrier_sync(saveQueue)
, мы уверены, что можем безопасно хранить новое изображение и что новые сэки или нагрузки будут ждать, пока это не закончится.
Код:
extension ViewController {
func saveImage(imageData:NSData, thumbnailData:NSData, date: Double) {
dispatch_barrier_sync(saveQueue) {
// create new objects in moc
guard let moc = self.managedContext else {
return
}
guard let fullRes = NSEntityDescription.insertNewObjectForEntityForName("FullRes", inManagedObjectContext: moc) as? FullRes, let thumbnail = NSEntityDescription.insertNewObjectForEntityForName("Thumbnail", inManagedObjectContext: moc) as? Thumbnail else {
// handle failed new object in moc
print("moc error")
return
}
//set image data of fullres
fullRes.imageData = imageData
//set image data of thumbnail
thumbnail.imageData = thumbnailData
thumbnail.id = date as NSNumber
thumbnail.fullRes = fullRes
// save the new objects
do {
try moc.save()
} catch {
fatalError("Failure to save context: \(error)")
}
// clear the moc
moc.refreshAllObjects()
}
}
}
Для загрузки изображения:
extension ViewController {
func loadImages(fetched:(images:[FullRes]?) -> Void) {
dispatch_async(saveQueue) {
guard let moc = self.managedContext else {
return
}
let fetchRequest = NSFetchRequest(entityName: "FullRes")
do {
let results = try moc.executeFetchRequest(fetchRequest)
let imageData = results as? [FullRes]
dispatch_async(dispatch_get_main_queue()) {
fetched(images: imageData)
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
return
}
}
}
}
Функции, используемые для масштабирования изображения:
extension CGSize {
func resizeFill(toSize: CGSize) -> CGSize {
let scale : CGFloat = (self.height / self.width) < (toSize.height / toSize.width) ? (self.height / toSize.height) : (self.width / toSize.width)
return CGSize(width: (self.width / scale), height: (self.height / scale))
}
}
extension UIImage {
func scale(toSize newSize:CGSize) -> UIImage {
// make sure the new size has the correct aspect ratio
let aspectFill = self.size.resizeFill(newSize)
UIGraphicsBeginImageContextWithOptions(aspectFill, false, 0.0);
self.drawInRect(CGRectMake(0, 0, aspectFill.width, aspectFill.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
причина это является и техническим и историческое, то, что текстовые протоколы почти всегда предпочитаются в мире Unix.
ну, это не действительно причина, но шаблон . Объяснение позади этого - то, что текстовые протоколы позволяют, Вы к видите , что продолжается в сети, просто выведя все, что проходит. Вам не нужен специализированный анализатор, как Вам нужно для TCP/IP. Это помогает отладить и легче поддержать.
Не только HTTP, но и много протоколов являются базирующимся текстом (например, FTP, POP3, SMTP, IMAP).
Вы могли бы хотеть смотреть на Искусство Программирования Unix для намного более подробного объяснения этой вещи Unix.
Много протоколов интернет-приложения используют более или менее простой текст для протокола (см. FTP, POP, SMTP, и т.д.).
Это делает совместимость и поиск и устранение неисправностей намного легче.
HTTP обозначает "Протокол передачи гипертекста".
Это было первоначально создано как способ вручить текстовые документы, следовательно основанный на тексте протокол.
то, Что мы делаем с HTTP теперь, далеко вне его исходного намерения.
С HTTP содержание из запроса является почти всегда порядками величины, больше, чем протокол наверху. Преобразование протокола в двоичную единицу сохранило бы очень мало пропускной способности и легкий debugability, который текстовый протокол предлагает легко козыри незначительные сбережения пропускной способности протокола двоичной синхронной передачи данных.
Как с раздел RFC 2616 3.7.1 для HTTP 1.1, ключевой идентификатор к строке команды или заголовка является текстовым разрывом строки CRLF; основанные на тексте прикладные протоколы помогают выполнить разговор (для поиска и устранения неисправностей) просто с клиентом Telnet. Это также помогает программировать с ReadLine () строки совпавшего текста и вызовы.
повреждение параметра CRLF также дает почти неограниченные abitrary расширения заголовка в отличие от фиксированного размера TCP или заголовки IP где твердые коды разрядными смещениями.
Таким образом, легче "считать" трафик или создать клиент или сервер?
можно дебатировать, помогает ли это на самом деле , но конечно который был намерением.
Исторически, все это начинает с RFC822 (СТАНДАРТ ДЛЯ ФОРМАТА ИНТЕРНЕТ-ТЕКСТОВЫХ СООБЩЕНИЙ ARPA), чья последняя версия является RFC5322 (интернет-Формат сообщения). SMTP (RFC 821) был одним из самого популярного протокола на основе RFC822. И, HTTP был подтвержден SMTP (Ваш почтовый протокол).