Czy można zapisać obrazy NSUserDefaults
jako obiekt, a następnie pobrać je do dalszego wykorzystania?
UWAGA! JEŚLI PRACUJESZ W SYSTEMIE iOS8 / XCODE6, ZOBACZ MOJĄ AKTUALIZACJĘ PONIŻEJ
Dla tych, którzy wciąż szukają odpowiedzi tutaj jest kod "zalecanego" sposobu zapisywania obrazu w NSUserDefaults. NIE POWINIENEŚ zapisywać danych obrazu bezpośrednio w NSUserDefaults!
Zapisz dane:
// Get image data. Here you can use UIImagePNGRepresentation if you need transparency
NSData *imageData = UIImageJPEGRepresentation(image, 1);
// Get image path in user's folder and store file with name image_CurrentTimestamp.jpg (see documentsPathForFileName below)
NSString *imagePath = [self documentsPathForFileName:[NSString stringWithFormat:@"image_%f.jpg", [NSDate timeIntervalSinceReferenceDate]]];
// Write image data to user's folder
[imageData writeToFile:imagePath atomically:YES];
// Store path in NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:imagePath forKey:kPLDefaultsAvatarUrl];
// Sync user defaults
[[NSUserDefaults standardUserDefaults] synchronize];
Czytaj dane:
NSString *imagePath = [[NSUserDefaults standardUserDefaults] objectForKey:kPLDefaultsAvatarUrl];
if (imagePath) {
self.avatarImageView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath]];
}
documentsPathForFileName:
- (NSString *)documentsPathForFileName:(NSString *)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
return [documentsPath stringByAppendingPathComponent:name];
}
Dla iOS8 / XCODE6 Jak wspomnieliśmy w komentarzach tmr i DevC, występuje problem z xcode6 / ios8. Różnica między procesem instalacji xcode5 i xcode 6 polega na tym, że xcode6 zmienia UUID aplikacji po każdym uruchomieniu w xcode (patrz wyróżniona część w ścieżce: / var / mobile / Containers / Data / Application / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / Documents / image.jpg).
Istnieją więc 2 obejścia:
Oto szybka wersja kodu jako bonus (z drugim podejściem):
Zapisz dane:
let imageData = UIImageJPEGRepresentation(image, 1)
let relativePath = "image_\(NSDate.timeIntervalSinceReferenceDate()).jpg"
let path = self.documentsPathForFileName(relativePath)
imageData.writeToFile(path, atomically: true)
NSUserDefaults.standardUserDefaults().setObject(relativePath, forKey: "path")
NSUserDefaults.standardUserDefaults().synchronize()
Czytaj dane:
let possibleOldImagePath = NSUserDefaults.standardUserDefaults().objectForKey("path") as String?
if let oldImagePath = possibleOldImagePath {
let oldFullPath = self.documentsPathForFileName(oldImagePath)
let oldImageData = NSData(contentsOfFile: oldFullPath)
// here is your saved image:
let oldImage = UIImage(data: oldImageData)
}
documentsPathForFileName:
func documentsPathForFileName(name: String) -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true);
let path = paths[0] as String;
let fullPath = path.stringByAppendingPathComponent(name)
return fullPath
}
Aby zapisać obraz w NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];
Aby pobrać obraz z NSUserDefaults:
NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key]; UIImage* image = [UIImage imageWithData:imageData];
źródło
Choć możliwe jest, aby zapisać
UIImage
sięNSUserDefaults
, że często nie jest zalecane, ponieważ nie jest to najbardziej skuteczny sposób na zapisywanie obrazów; bardziej wydajnym sposobem jest zapisanie obrazu w aplikacjiDocuments Directory
.Na potrzeby tego pytania załączam odpowiedź na Twoje pytanie wraz z bardziej efektywnym sposobem zapisania pliku
UIImage
.NSUserDefaults (niezalecane)
Zapisywanie do NSUserDefaults
Ta metoda umożliwia zapisanie dowolnego pliku
UIImage
doNSUserDefaults
.-(void)saveImageToUserDefaults:(UIImage *)image ofType:(NSString *)extension forKey:(NSString *)key { NSData * data; if ([[extension lowercaseString] isEqualToString:@"png"]) { data = UIImagePNGRepresentation(image); } else if ([[extension lowercaseString] isEqualToString:@"jpg"]) { data = UIImageJPEGRepresentation(image, 1.0); } NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:data forKey:key]; [userDefaults synchronize]; }
Tak to nazywasz:
[self saveImageToUserDefaults:image ofType:@"jpg" forKey:@"myImage"]; [[NSUserDefaults standardUserDefaults] synchronize];
Ładowanie z NSUserDefaults
Ta metoda umożliwia załadowanie dowolnego pliku
UIImage
zNSUserDefaults
.-(UIImage *)loadImageFromUserDefaultsForKey:(NSString *)key { NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults]; return [UIImage imageWithData:[userDefaults objectForKey:key]]; }
Tak to nazywasz:
UIImage * image = [self loadImageFromUserDefaultsForKey:@"myImage"];
Lepsza alternatywa
Zapisywanie do katalogu dokumentów
Metoda ta pozwala na zapisanie dowolnego
UIImage
doDocuments Directory
wewnątrz aplikacji.-(void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath { if ([[extension lowercaseString] isEqualToString:@"png"]) { [UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"png"]] options:NSAtomicWrite error:nil]; } else if ([[extension lowercaseString] isEqualToString:@"jpg"] || [[extension lowercaseString] isEqualToString:@"jpeg"]) { [UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]] options:NSAtomicWrite error:nil]; } else { NSLog(@"Image Save Failed\nExtension: (%@) is not recognized, use (PNG/JPG)", extension); } }
Tak to nazywasz:
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; [self saveImage:image withFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];
Ładowanie z katalogu dokumentów
Ta metoda umożliwia załadowanie dowolnego
UIImage
z plików aplikacjiDocuments Directory
.-(UIImage *)loadImageWithFileName:(NSString *)fileName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath { UIImage * result = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", directoryPath, fileName, [extension lowercaseString]]]; return result; }
Tak to nazywasz:
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; UIImage * image = [self loadImageWithFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];
Inna alternatywa
Zapisywanie UIImage w bibliotece zdjęć
Ta metoda umożliwia zapisanie dowolnego
UIImage
na urządzeniuPhoto Library
i jest wywoływana w następujący sposób:UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
Zapisywanie wielu UIImage w bibliotece zdjęć
Ta metoda umożliwia zapisanie wielu plików
UIImages
na urządzeniuPhoto Library
.-(void)saveImagesToPhotoAlbums:(NSArray *)images { for (int x = 0; x < [images count]; x++) { UIImage * image = [images objectAtIndex:x]; if (image != nil) UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); } }
Tak to nazywasz:
[self saveImagesToPhotoAlbums:images];
Gdzie
images
jest twójNSArray
składUIImages
.źródło
inDirectory:(NSString *)directoryPath
- czy możesz nazwać go jak chcesz, np. „MyAppData”?Dla Swift 4
Prawie próbowałem wszystkiego w tej kwestii, ale nikt nie pracuje dla mnie. i znalazłem swoje rozwiązanie. najpierw utworzyłem rozszerzenie dla UserDefaults, jak poniżej, a potem właśnie wywołałem metody get and set.
extension UserDefaults { func imageForKey(key: String) -> UIImage? { var image: UIImage? if let imageData = data(forKey: key) { image = NSKeyedUnarchiver.unarchiveObject(with: imageData) as? UIImage } return image } func setImage(image: UIImage?, forKey key: String) { var imageData: NSData? if let image = image { imageData = NSKeyedArchiver.archivedData(withRootObject: image) as NSData? } set(imageData, forKey: key) } }
aby ustawić obraz jako tło w settingsVC Użyłem kodu poniżej.
let croppedImage = cropImage(selectedImage, toRect: rect, viewWidth: self.view.bounds.size.width, viewHeight: self.view.bounds.size.width) imageDefaults.setImage(image: croppedImage, forKey: "imageDefaults")
w mainVC:
let bgImage = imageDefaults.imageForKey(key: "imageDefaults")!
źródło
Dla szybkiej 2.2
Przechować:
NSUserDefaults.standardUserDefaults().setObject(UIImagePNGRepresentation(chosenImage), forKey: kKeyImage)
Aby odzyskać:
if let imageData = NSUserDefaults.standardUserDefaults().objectForKey(kKeyImage), let image = UIImage(data: imageData as! NSData){ // use your image here... }
źródło
Tak, technicznie możliwe, jak w
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:@"foo"];
Ale nie jest to zalecane, ponieważ plists nie są odpowiednimi miejscami dla dużych blobów danych binarnych, zwłaszcza Prefs użytkownika. Byłoby lepiej zapisać obraz w folderze dokumentów użytkownika i przechowywać odniesienie do tego obiektu jako adres URL lub ścieżkę.
źródło
Dla formatu Swift 3 i JPG
Zarejestruj domyślny obraz:
UserDefaults.standard.register(defaults: ["key":UIImageJPEGRepresentation(image, 100)!])
Zapisać obraz :
UserDefaults.standard.set(UIImageJPEGRepresentation(image, 100), forKey: "key")
Załaduj obraz:
let imageData = UserDefaults.standard.value(forKey: "key") as! Data let imageFromData = UIImage(data: imageData)!
źródło
Z dokumentacji Apple,
Możesz zapisać obraz w ten sposób: -
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation([UIImage imageNamed:@"yourimage.gif"])forKey:@"key_for_your_image"];
I przeczytaj tak: -
NSData* imageData = [[NSUserDefaults standardUserDefaults]objectForKey:@"key_for_your_image"]; UIImage* image = [UIImage imageWithData:imageData];
źródło
Jest to technicznie możliwe, ale nie jest zalecane. Zamiast tego zapisz obraz na dysku. NSUserDefaults jest przeznaczone dla małych ustawień, a nie dużych plików danych binarnych.
źródło
Zapisz obraz w NSUserDefault:
NSData *imageData; // create NSData-object from image imageData = UIImagePNGRepresentation([dic objectForKey:[NSString stringWithFormat:@"%d",i]]); // save NSData-object to UserDefaults [[NSUserDefaults standardUserDefaults] setObject:imageData forKey:[NSString stringWithFormat:@"%d",i]];
Załaduj obraz z NSUserDefault:
NSData *imageData; // Load NSData-object from NSUserDefault imageData = [[NSUserDefaults standardUserDefaults] valueForKey:[NSString stringWithFormat:@"%d",i]]; // get Image from NSData [image setObject:[UIImage imageWithData:imageData] forKey:[NSString stringWithFormat:@"%d",i]];
źródło
Tak, możesz użyć. Ale ponieważ służy do przechowywania preferencji, możesz lepiej zapisywać obrazy w folderze dokumentów.
W
NSUserDefaults
razie potrzeby możesz mieć ścieżkę w pliku.źródło
Ponieważ to pytanie ma wysoki indeks wyszukiwania Google - oto odpowiedź @ NikitaTook w dzisiejszych czasach, tj. Swift 3 i 4 (z obsługą wyjątków).
Uwaga: Ta klasa jest przeznaczona wyłącznie do odczytu i zapisu obrazów w formacie JPG w systemie plików.
Userdefaults
Rzeczy powinny być obsługiwane poza nim.writeFile
pobiera nazwę pliku obrazu jpg (z rozszerzeniem .jpg) iUIImage
samego siebie i zwraca true, jeśli jest w stanie zapisać, lub zwraca false, jeśli nie może zapisać obrazu, w którym to momencie możesz zapisać obraz, wUserdefaults
którym byłby planem tworzenia kopii zapasowych lub po prostu spróbuj jeszcze raz.readFile
Funkcja przyjmuje w nazwie pliku obrazu i zwracaUIImage
, jeśli nazwa obrazu przekazywane do tej funkcji znajduje się wówczas zwraca ten obraz innego po prostu zwraca domyślny obraz zastępczy z folderu aktywami o aplikacji (w ten sposób można uniknąć nieprzyjemnych wypadków lub innych dziwne zachowania).import Foundation import UIKit class ReadWriteFileFS{ func writeFile(_ image: UIImage, _ imgName: String) -> Bool{ let imageData = UIImageJPEGRepresentation(image, 1) let relativePath = imgName let path = self.documentsPathForFileName(name: relativePath) do { try imageData?.write(to: path, options: .atomic) } catch { return false } return true } func readFile(_ name: String) -> UIImage{ let fullPath = self.documentsPathForFileName(name: name) var image = UIImage() if FileManager.default.fileExists(atPath: fullPath.path){ image = UIImage(contentsOfFile: fullPath.path)! }else{ image = UIImage(named: "user")! //a default place holder image from apps asset folder } return image } } extension ReadWriteFileFS{ func documentsPathForFileName(name: String) -> URL { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let path = paths[0] let fullPath = path.appendingPathComponent(name) return fullPath } }
źródło
Swift 4.x
Xcode 11.x
func saveImageInUserDefault(img:UIImage, key:String) { UserDefaults.standard.set(img.pngData(), forKey: key) } func getImageFromUserDefault(key:String) -> UIImage? { let imageData = UserDefaults.standard.object(forKey: key) as? Data var image: UIImage? = nil if let imageData = imageData { image = UIImage(data: imageData) } return image }
źródło