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とxcode6のインストールプロセスの違いは、xcode6xcodeで実行されるたびにアプリのUUIDを変更することです(パスの強調表示された部分:/ var / mobile / Containers / Data / Application / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / Documents / image.jpg)。

したがって、2つの回避策があります。

  1. その問題をスキップしてください。アプリが実際のデバイスにインストールされると、UUIDが変更されることはありません(実際には変更されますが、新しいアプリです)
  2. 必要なフォルダー(この場合はアプリのルート)への相対パスを保存します

ボーナスとしてのコードの迅速なバージョンは次のとおりです(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
コードが初めて機能せず、ディスクからイメージを取得できませんでした。ドキュメントフォルダへのパスは、アプリの実行間で異なりました。絶対パスと相対パスの問題になる可能性がありますか?コードは1つの* imagePathに書き込んでいましたが、アプリの次の実行では、ファイルを取得するために別の* imagePathが必要でした。簡単な解決策は、ファイル名のみをnsuserdefaultsに保存することでした。次のアプリの実行時に、ドキュメントのフォルダーパスを再取得し、ファイル名を追加すると、残りのコードがうまく機能しました。(ありがとうNikita Took)
tmr 2014

それで、主にデバイスで実行している場合、本質的にiOS8 / Xcode 6の問題は完全に無効ですか?
micnguyen 2014年

追加したいのですが、PNGRepresentationを使用しても、Orientationメタデータは自動的に保存されません。手動で行うか、JPEGバージョンを使用する必要があります。
micnguyen 2014年

その場所に画像を保存するとiCloudデータに影響しますか?つまり、ユーザーが生成したものでなければ、その場所に保存するべきではありませんか?
クリス・ハリソン

1
@NikitaTook画像の配列はどうですか?どうすればそれを行うことができますか?
GJZ 2016

138

NSUserDefaultsに画像を保存するには:

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

NSUserDefaultsから画像を取得するには:

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

17
技術的に正しい、積極的に推奨されていません。NSUserDefaultsはplistに出力しますが、これは明らかに生の画像データの場所ではありません。
クリススタンパー

@cdstamper最近、plistがmacosxにバイナリ形式で保存されていることを読みました。拡張機能とそれを含むアプリの間で使用される場合、IPCが使用されます(ファイルはその間に使用される場合と使用されない場合があります)。だから問題は何ですか?
トッド

この質問はiPhone / iPadに対応しています。とにかく、Appleのドキュメントが別の方法を推奨するまで、NSUserDefaultsは小さなアプリケーション設定用であり、ストレージ用ではありません。指定されているように(developer.apple.com/Library/mac/documentation/Cocoa/Reference/…)、「NSUserDefaultsクラスは、float、double、integers、Boolean、URLなどの一般的なタイプにアクセスするための便利なメソッドを提供します」
chris Stamper

@cdstamperでは、たとえば、ユーザーがログインしているアプリのプロファイル画像を保存するための推奨される方法は何ですか?1つの画像を保存するためだけにCoreDataを使用したくないので、画像を表示する必要があるたびにクラウドストレージ/データベースにアクセスしたいのですが、高価で不要です。
AnBisw 2017

2
@annjawnはそれをファイルシステムに書き込み、URLをNSUserDefaultsに保存します
chris Stamper

29

保存することも可能であるがUIImageためにNSUserDefaults、それは、画像を保存するための最も効率的な方法ではないとして、それは多くの場合、推奨されません。より効率的な方法は、アプリケーションの画像を保存することですDocuments Directory

この質問の目的のために、私はあなたの質問への回答と、を保存するより効率的な方法を添付しましたUIImage


NSUserDefaults(非推奨)

NSUserDefaultsに保存する

このメソッドを使用すると、任意のものUIImageをに保存できますNSUserDefaults

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

この場合、引数としてDocumentsDirectoryパスを使用しました。ただし、アプリのサンドボックス/バンドル内でアクセスできる任意のディレクトリを使用できます。
フェルナンドセルバンテス

11

スイフト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?)
Oleksandr20年

聞かせて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、integers、Booleans、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

この質問はグーグル検索インデックスが高いので、今日の日と年齢での@NikitaTookの回答、つまりSwift 3と4(例外処理を除く)です。

注:このクラスは、JPG形式の画像をファイルシステムに読み書きするためだけに作成されています。ザ・Userdefaultsものはそれの外側を処理する必要があります。

writeFilejpg画像のファイル名(拡張子は.jpg)とUIImageそれ自体を取り込んで、保存できる場合はtrueを返し、画像を書き込めない場合は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.