NSUserDefaults में चित्र सहेजें?


80

क्या छवियों 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]];
}

डाक्यूमेंटफ़ॉर्फ़ फ़ाइलनाम:

- (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 एप्स को Ucode में प्रत्येक रन के बाद UUID बदलता है (पथ में hightlighted भाग देखें: / var / मोबाइल / कंटेनर / डेटा / एप्लिकेशन / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / दस्तावेज़ / दस्तावेज़ image.jpg)।

तो वहाँ 2 workarounds हैं:

  1. उस समस्या को छोड़ दें, जैसा कि एक बार वास्तविक डिवाइस पर इंस्टॉल किया गया ऐप यूयूआईडी को कभी नहीं बदलता है (वास्तव में यह करता है, लेकिन यह नया ऐप है)
  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)
}

डाक्यूमेंटफ़ॉर्फ़ फ़ाइलनाम:

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 में केवल फ़ाइल नाम को बचाने के लिए था, और अगले ऐप रन पर, दस्तावेज़ फ़ोल्डर पथ को पुनः प्राप्त करें, फ़ाइल नाम को जोड़ें, और बाकी कोड ने बहुत काम किया! (
साभार

तो अनिवार्य रूप से iOS8 / Xcode 6 समस्या पूरी तरह से शून्य है अगर मुख्य रूप से डिवाइस पर चल रहा है?
माइक्रोएयुन

मैं सिर्फ जोड़ना चाहता हूं: PNGRepresentation का उपयोग करने से ओरिएंटेशन मेटाडेटा स्वचालित रूप से सहेज नहीं होगा। आपको इसे मैन्युअल रूप से करना होगा, या केवल JPEG संस्करण का उपयोग करना होगा।
10

क्या उस स्थान पर छवियों को सहेजना iCloud डेटा को प्रभावित करेगा - यदि यह उपयोगकर्ता द्वारा उत्पन्न नहीं किया गया है तो हमें उस स्थान पर सहेजना नहीं चाहिए?
क्रिस हैरिसन

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 को आउटपुट करता है, जो स्पष्ट रूप से कच्ची छवि डेटा के लिए जगह नहीं है।
क्रिस स्टैपर

@cdstamper मैंने पढ़ा है कि एक ओएस बस्ट प्रारूप में इन दिनों मैक ओएसएक्स पर संग्रहीत है। यदि एक एक्सटेंशन और ऐप युक्त IPC के बीच उपयोग किया जाता है (बीच में एक फ़ाइल का उपयोग किया जा सकता है या नहीं भी किया जा सकता है)। तो समस्या क्या है?
टोड

यह प्रश्न iPhone / iPad को संबोधित करता है। भले ही, जब तक कि ऐप्पल के डॉक्टर की सिफारिश नहीं होती है, तब तक NSUserDefaults छोटी एप्लिकेशन प्राथमिकताओं के लिए है और भंडारण के लिए नहीं। जैसा कि निर्दिष्ट किया गया है ( developer.apple.com/Library/mac/documentation/Cocoa/Reference/… ), "NSUserDefaults वर्ग फ़्लोट्स, डबल्स, पूर्णांक, बूलियन्स और URL जैसे सामान्य प्रकारों तक पहुँचने के लिए सुविधा विधियाँ प्रदान करता है"
क्रिस स्टॉपर

@ LCDstamper इसलिए स्टोर करने का अनुशंसित तरीका क्या है, यह बताता है कि किसी ऐप के लिए प्रोफ़ाइल छवि जहां उपयोगकर्ता लॉग इन है? मैं CoreData का उपयोग केवल 1 छवि को संग्रहीत करने के लिए नहीं करना चाहता और मुझे ऐसा लगता है कि क्लाउड स्टोरेज / db को हर बार हिट करने के लिए मुझे छवि दिखाने की आवश्यकता है कि यह महंगे / गैर-आवश्यक है।
अनीबस

2
@annjawn ने इसे केवल फाइलसिस्टम में लिखा है, और URL को NSUserDefaults में संग्रहीत किया है
क्रिस

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

फोटो लाइब्रेरी के लिए कई UIImages सहेजा जा रहा है

यह विधि आपको 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" की तरह जो चाहें कह सकते हैं ??
सुपरटेककोनॉफ

खैर इस मामले में, मैंने तर्क के रूप में दस्तावेज़ निर्देशिका पथ का उपयोग किया। हालाँकि, आप अपने ऐप के सैंडबॉक्स / बंडल में किसी भी निर्देशिका का उपयोग कर सकते हैं।
फर्नांडो सेर्वेंटेस

11

स्विफ्ट 4 के लिए

मैंने इस प्रश्न में लगभग सब कुछ आजमाया लेकिन मेरे लिए कोई काम नहीं किया गया। और मुझे अपना हल मिल गया। पहले मैंने नीचे दिए गए UserDefaults के लिए एक एक्सटेंशन बनाया, फिर बस बुलाया और तरीकों को सेट किया।

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

सेटिंग में पृष्ठभूमि के रूप में छवि सेट करने के लिए मैंने नीचे दिए गए कोड का उपयोग किया।

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")!


let इमेजडिफॉल्ट्स = यूजरडिफॉल्ट्स.स्टैंडर्ड
बिलाल

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

लेकिन सलाह देने योग्य नहीं है क्योंकि बाइनरी डेटा के विशेष रूप से उपयोगकर्ता वरीयता के बड़े ब्लूब के लिए उपयुक्त स्थान नहीं हैं। उपयोगकर्ता डॉक्स फ़ोल्डर में छवि को सहेजना और URL या पथ के रूप में उस ऑब्जेक्ट के संदर्भ को संग्रहीत करना बेहतर होगा।


4

के लिए स्विफ्ट 3 और JPG प्रारूप

डिफ़ॉल्ट छवि पंजीकृत करें:

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 वर्ग सामान्य प्रकार जैसे फ़्लोट्स, डबल्स, पूर्णांक, बूलियन और 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 खोज सूचकांक है - यहाँ @ निकिताटुक का जवाब आज के दिन और उम्र में है अर्थात स्विफ्ट 3 और 4 (अपवाद हैंडलिंग के साथ)।

नोट: यह वर्ग पूरी तरह से फाइल सिस्टम पर JPG फॉर्मेट की छवियों को पढ़ने और लिखने के लिए लिखा गया है। Userdefaultsसामान इसके बाहर संभाला जाना चाहिए।

writeFileअपने जेपीजी चित्र (.jpg विस्तार के साथ) की फ़ाइल के नाम में ले जाता है और UIImageअपने आप में और सच रिटर्न अगर यह बचाने वरना रिटर्न झूठी अगर यह छवि लिखने में असमर्थ है करने में सक्षम है, जो बिंदु पर आप छवि को स्टोर कर सकते में 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

स्विफ्ट 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
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.