NSUserDefaults에 이미지를 저장 하시겠습니까?


답변:


84

주의! iOS8 / XCODE6에서 작업하는 경우 아래 업데이트를 참조하십시오.

여전히 대답을 찾는 사람들을 위해 NSUserDefaults에 이미지를 저장하는 "권장되는"방법의 코드가 있습니다. 이미지 데이터를 NSUserDefaults에 직접 저장해서는 안됩니다!

데이터 쓰기 :

// 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];

데이터 읽기 :

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];
}

iOS8 / XCODE6의 경우 아래 주석에서 언급 한 tmr 및 DevC와 같이 xcode6 / ios8에 문제가 있습니다. xcode5와 xcode 6 설치 프로세스의 차이점은 xcode6 은 xcode에서 실행될 때마다 앱 UUID를 변경 한다는 것입니다 (경로에서 강조 표시된 부분 참조 : / var / mobile / Containers / Data / Application / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / Documents / image.jpg).

따라서 두 가지 해결 방법이 있습니다.

  1. 앱이 실제 기기에 설치되면 UUID가 변경되지 않으므로 해당 문제를 건너 뜁니다 (실제로 변경되지만 새로운 앱임).
  2. 필요한 폴더에 상대 경로를 저장합니다 (이 경우 앱의 루트).

다음은 보너스로 빠른 코드 버전입니다 (두 번째 접근 방식).

데이터 쓰기 :

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

데이터 읽기 :

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
}

2
코드가 처음으로 작동하지 않았고 디스크에서 이미지를 검색 할 수 없었습니다. 문서 폴더의 경로가 앱 실행마다 다릅니다. 절대 경로와 상대 경로의 문제가 될 수 있습니까? 코드는 하나의 * imagePath에 작성되었지만 다음 번에 앱을 실행할 때 파일을 가져 오기 위해 다른 * imagePath가 필요했습니다. 간단한 해결책은 nsuserdefaults에 파일 이름 만 저장하는 것이었고 다음 앱 실행시 문서 폴더 경로를 다시 가져오고 파일 이름을 추가하고 나머지 코드는 훌륭하게 작동했습니다! (감사합니다 Nikita Took)
tmr 2014 년

따라서 기본적으로 iOS8 / Xcode 6 문제는 주로 장치에서 실행되는 경우 완전히 무효입니까?
micnguyen 2014 년

추가하고 싶습니다 : PNGRepresentation을 사용하면 Orientation 메타 데이터가 자동으로 저장되지 않습니다. 수동으로 수행하거나 JPEG 버전을 사용해야합니다.
micnguyen 2014 년

해당 위치에 이미지를 저장하면 iCloud 데이터에 영향을 미칩니다. 즉, 사용자가 생성하지 않은 경우 해당 위치에 저장하면 안됩니까?
Chris Harrison

1
@NikitaTook 이미지 배열은 어떻습니까? 어떻게할까요?
GJZ

138

NSUserDefaults에 이미지를 저장하려면 :

[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];

NSUserDefaults에서 이미지를 검색하려면 :

NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];

17
기술적으로 정확하고 긍정적으로 권장하지 않습니다. NSUserDefaults는 plist에 출력하며, 이는 분명히 원시 이미지 데이터의 장소가 아닙니다.
chris stamper

@cdstamper 나는 plist가 요즘 mac osx에서 바이너리 형식으로 저장된다는 것을 읽었습니다. 확장자와 포함 된 앱 사이에 사용되는 경우 IPC가 사용됩니다 (파일은 사이에 사용되거나 사용되지 않을 수 있음). 그래서 무엇이 문제입니까?
Todd

이 질문은 iPhone / iPad에 대한 것입니다. 그럼에도 불구하고 Apple의 문서에서 달리 권장 할 때까지 NSUserDefaults는 스토리지가 아닌 작은 애플리케이션 환경 설정을위한 것입니다. 지정된대로 ( developer.apple.com/Library/mac/documentation/Cocoa/Reference/… ), "NSUserDefaults 클래스는 float, double, 정수, 부울 및 URL과 같은 일반 유형에 액세스하기위한 편리한 메소드를 제공합니다"
chris stamper

@cdstamper 그렇다면 사용자가 로그인 한 앱의 프로필 이미지를 저장하는 권장 방법은 무엇입니까? 이미지 1 개를 저장하기 위해 CoreData를 사용하고 싶지 않으며 이미지가 비싸거나 불필요하다는 것을 보여줄 필요가있을 때마다 클라우드 스토리지 / db를 치는 느낌이 듭니다.
AnBisw

2
단지 @annjawn 파일 시스템에 기록하고, NSUserDefaults의 URL 저장
크리스 스탬퍼

29

을 저장할 수 있지만 UIImage할 수 NSUserDefaults는 이미지를 저장하는 가장 효율적인 방법이 아니다, 그것은 자주 사용하지 않는 것이 좋습니다; 더 효율적인 방법은 이미지를 응용 프로그램의 Documents Directory.

이 질문의 목적을 위해 귀하의 질문에 대한 답변과 함께 UIImage.


NSUserDefaults (권장하지 않음)

NSUserDefaults에 저장

이 방법을 사용하면 모든 파일 UIImageNSUserDefaults.

-(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];
}

이것이 당신이 그것을 부르는 방법입니다.

[self saveImageToUserDefaults:image ofType:@"jpg" forKey:@"myImage"];
[[NSUserDefaults standardUserDefaults] synchronize];

NSUserDefaults에서로드

이 방법을 사용하면 하나를로드 할 수 있습니다 UIImage에서 NSUserDefaults.

-(UIImage *)loadImageFromUserDefaultsForKey:(NSString *)key {
    NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
    return [UIImage imageWithData:[userDefaults objectForKey:key]];
}

이것이 당신이 그것을 부르는 방법입니다.

UIImage * image = [self loadImageFromUserDefaultsForKey:@"myImage"];

더 나은 대안

문서 디렉토리에 저장

이 방법을 사용하면 어떤 저장할 수 있습니다 UIImage받는 사람을 Documents Directory응용 프로그램 내.

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

이것이 당신이 그것을 부르는 방법입니다.

NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:image withFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];

문서 디렉토리에서로드

이 메서드를 사용하면 UIImage응용 프로그램의 Documents Directory.

-(UIImage *)loadImageWithFileName:(NSString *)fileName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
    UIImage * result = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", directoryPath, fileName, [extension lowercaseString]]];

    return result;
}

이것이 당신이 그것을 부르는 방법입니다.

NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];

다른 대안

사진 라이브러리에 UIImage 저장

이 메서드를 사용하면 UIImage장치의에 모든 항목을 저장할 수 Photo Library있으며 다음과 같이 호출됩니다.

UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

여러 UIImage를 사진 라이브러리에 저장

이 방법을 사용하면 UIImages장치의 Photo 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);
    }
}

이것이 당신이 그것을 부르는 방법입니다.

[self saveImagesToPhotoAlbums:images];

어디 images당신입니다 NSArray구성 UIImages.


그레이트 포스트! 입력에 대해 어떤 디렉토리를 설정할지 어떻게 알 inDirectory:(NSString *)directoryPath수 있습니까? "myAppData"와 같이 원하는대로 호출 할 수 있습니까 ??
Supertecnoboff

이 경우 문서 디렉토리 경로를 인수로 사용했습니다. 그러나 앱의 샌드 박스 / 번들 내에서 액세스 할 수있는 모든 디렉토리를 사용할 수 있습니다.
페르난도 세르반테스

11

Swift 4의 경우

이 질문에서 거의 모든 것을 시도했지만 아무도 나를 위해 일하지 않았습니다. 내 해결책을 찾았습니다. 먼저 아래와 같이 UserDefaults에 대한 확장을 만든 다음 get 및 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)
    } 
}

settingsVC에서 이미지를 배경으로 설정하려면 아래 코드를 사용했습니다.

let croppedImage = cropImage(selectedImage, toRect: rect, viewWidth: self.view.bounds.size.width, viewHeight: self.view.bounds.size.width)

imageDefaults.setImage(image: croppedImage, forKey: "imageDefaults")

mainVC에서 :

let bgImage = imageDefaults.imageForKey(key: "imageDefaults")!

imageDefaults)?
올렉산드르

하자 imageDefaults = UserDefaults.standard
빌랄 Şimşek

8

신속한 2.2

저장하려면 :

NSUserDefaults.standardUserDefaults().setObject(UIImagePNGRepresentation(chosenImage), forKey: kKeyImage)

검색하려면 :

if let imageData = NSUserDefaults.standardUserDefaults().objectForKey(kKeyImage),
            let image = UIImage(data: imageData as! NSData){
            // use your image here...
}

5

예, 기술적으로 가능합니다.

[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:@"foo"];

그러나 plist는 큰 이진 데이터, 특히 사용자 환경 설정에 적합한 장소가 아니기 때문에 권장되지 않습니다. 이미지를 사용자 문서 폴더에 저장하고 해당 개체에 대한 참조를 URL 또는 경로로 저장하는 것이 좋습니다.


4

대한 스위프트 3JPG 형식

기본 이미지 등록 :

UserDefaults.standard.register(defaults: ["key":UIImageJPEGRepresentation(image, 100)!])

이미지를 저장 :

UserDefaults.standard.set(UIImageJPEGRepresentation(image, 100), forKey: "key")

로드 이미지 :

let imageData = UserDefaults.standard.value(forKey: "key") as! Data
let imageFromData = UIImage(data: imageData)!

3

애플 문서에서

NSUserDefaults 클래스는 float, double, 정수, 부울 및 URL과 같은 일반적인 유형에 액세스하기위한 편리한 메서드를 제공합니다. 기본 객체는 속성 목록, 즉 NSData, NSString, NSNumber, NSDate, NSArray 또는 NSDictionary의 인스턴스 (또는 컬렉션의 경우 인스턴스 조합) 여야합니다. 다른 유형의 객체를 저장하려면 일반적으로 NSData의 인스턴스를 생성하기 위해 보관해야합니다.

다음과 같이 이미지를 저장할 수 있습니다.

[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation([UIImage imageNamed:@"yourimage.gif"])forKey:@"key_for_your_image"];

그리고 다음과 같이 읽으십시오.

 NSData* imageData = [[NSUserDefaults standardUserDefaults]objectForKey:@"key_for_your_image"];
    UIImage* image = [UIImage imageWithData:imageData];

2

기술적으로는 가능하지만 권장하지 않습니다. 대신 이미지를 디스크에 저장하십시오. NSUserDefaults는 큰 바이너리 데이터 파일이 아닌 작은 설정을위한 것입니다.


1

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]];

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]];

1

네, 사용할 수 있습니다. 그러나 환경 설정 저장을위한 것이므로 문서 폴더에 이미지를 더 잘 저장할 수 있습니다.

NSUserDefaults필요한 경우에 경로를 가질 수 있습니다 .


1

이 질문은 Google 검색 색인이 높기 때문에 오늘 날과 시대에 @NikitaTook의 답변, 즉 Swift 3 및 4 (예외 처리 포함)가 있습니다.

참고 :이 클래스는 파일 시스템에서 JPG 형식의 이미지를 읽고 쓰는 용도로만 작성되었습니다. 그만큼Userdefaults물건은 외부를 처리해야한다.

writeFile(.JPG 확장자)하여 JPG 이미지의 파일 이름에 취해 UIImage자체 진정한 수익을 당신이 이미지를 저장할 수있는 시점에서,이 이미지를 기록 할 수없는 경우는 false를 저장하거나 다른 반환 할 수있는 경우에 Userdefaults어떤 백업 계획이 될 수도 있고 한 번 더 다시 시도하십시오. 이 readFile함수는 이미지 파일 이름을 가져와를 반환합니다 UIImage.이 함수에 전달 된 이미지 이름이 발견되면 해당 이미지를 반환합니다. 그렇지 않으면 앱의 자산 폴더에서 기본 자리 표시 자 이미지 만 반환합니다 (이 방법을 사용하면 불쾌한 충돌이나 기타 이상한 행동).

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

1

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
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.