2014-10-09 7 views
15

मैं स्विफ्ट के साथ छवियों को प्रदर्शित और सहेजने की कोशिश कर रहा हूं। पहली हिट पर, यह इमेजव्यू पर रिमोट इमेज दिखाता है, दूसरी हिट पर यह रिक्त इमेजव्यू दिखाता है इसके बजाय यह स्थानीय छवि होना चाहिए जो पहली हिट पर सहेजा जाता है।स्विफ्ट के साथ एक दूरस्थ छवि को कैसे सहेजने के लिए?

var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String 
    var imagePath = paths.stringByAppendingPathComponent("images/\(id)/logo.jpg") 
    var checkImage = NSFileManager.defaultManager() 

    if (checkImage.fileExistsAtPath(imagePath)) { 
     let getImage = UIImage(contentsOfFile: imagePath) 
     self.image?.image = getImage 
    } else { 
     dispatch_async(dispatch_get_main_queue()) { 
      let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage))) 
      UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true) 
      self.image?.image = getImage 
     } 
    } 

संपादित करें: यह मेरे लिए काम करता है।

var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String 
var dirPath = paths.stringByAppendingPathComponent("images/\(id)") 
var imagePath = paths.stringByAppendingPathComponent("images/\(id)/logo.jpg") 
var checkImage = NSFileManager.defaultManager() 

if (checkImage.fileExistsAtPath(imagePath)) { 
    let getImage = UIImage(contentsOfFile: imagePath) 
    self.image?.image = getImage 
} else { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { 
     checkImage.createDirectoryAtPath(dirPath, withIntermediateDirectories: true, attributes: nil, error: nil) 
     let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage))) 
     UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true) 

     dispatch_async(dispatch_get_main_queue()) { 
      self.image?.image = getImage 
      return 
     } 
    } 
} 

उत्तर

18

अपने मुख्य सवाल का जवाब करने के लिए, आप गलत UIImage प्रारंभकर्ता कॉल कर रहे हैं। आप इसके अतिरिक्त तेज 3.

में तेजी से 2 में UIImage(contentsOfFile: imagePath) और UIImage(contentsOf: imagePath) बुला जाना चाहिए, ऐसा लगता है कि आप dispatch_async (या तेजी से 3 में DispatchQueue) के साथ पृष्ठभूमि में अपने रिमोट लाने का प्रयास कर रहे हैं, लेकिन आप गुजर रहे हैं यह मुख्य कतार है, इसलिए आप वास्तव में उस के साथ मुख्य/यूआई थ्रेड को अवरुद्ध कर रहे हैं। इसके बजाय आप पृष्ठभूमि कतारों से एक के लिए यह प्रेषण चाहिए और फिर वापस मुख्य कतार जब आप वास्तव में अपने यूआई में छवि स्थापित करने के लिए प्रेषण:

स्विफ्ट 3:

DispatchQueue.global(qos: DispatchQoS.background.qosClass).async { 
    do { 
     let data = try Data(contentsOf: URL(string: self.remoteImage)!) 
     let getImage = UIImage(data: data) 
     try UIImageJPEGRepresentation(getImage!, 100)?.write(to: imagePath) 
     DispatchQueue.main.async { 
      self.image?.image = getImage 
      return 
     } 
    } 
    catch { 
      return 
    } 
} 

स्विफ्ट 2:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { 
    let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: self.remoteImage))) 
    UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true) 

    dispatch_async(dispatch_get_main_queue()) { 
     self.image?.image = getImage 
     return 
    } 
} 

@Rob's answer पुन: अपनी रिमोट छवि लाने और इसे सहेजना वास्तव में ऐसा करने का सबसे अच्छा तरीका है।

+0

धन्यवाद, मैंने इसे UIImage में बदल दिया (ContentOfFile: imagePath)।लेकिन जब मैं dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) पर प्रेषण बदलता हूं) यह दूरस्थ छवि भी नहीं दिखा रहा है। – bilmiyore

+0

मैंने अभी आपके कोड में संपादन देखा है ... मैं अपना जवाब अपडेट करूंगा। –

+0

धन्यवाद, मुझे लगता है कि प्रेषण अब बेहतर काम करता है। लेकिन फिर भी मैं स्थानीय रूप से छवियों को लोड नहीं कर सकता। मुझे लगता है कि "var imagePath = paths.stringByAppendingPathComponent (" images/\ (id) /logo.jpg ")" समस्या है क्योंकि "अगर ब्लॉक" बिल्कुल दिखाई नहीं देता है। – bilmiyore

10

आपका कोड जो मुख्य कतार में NSData(contentsOfURL:) (अब Data(contentsOf:) के रूप में जाना जाता है) भेजता है। यदि आप दूरस्थ छवि का अनुरोध करने के लिए उस तुल्यकालिक विधि का उपयोग करने जा रहे हैं, तो आपको इसे पृष्ठभूमि कतार पर करना चाहिए।

इसके अलावा, आप, NSData ले जा रहे हैं यह एक UIImage को बदलने, और फिर इसे एक NSData को बदलने वापस UIImageJPEGRepresentation का उपयोग कर। UIImageJPEGRepresentation हालांकि राउंड-ट्रिप न करें क्योंकि आप मूल पेलोड बदल देंगे और संपत्ति के आकार को बदल देंगे।

DispatchQueue.global().async { 
    do { 
     let data = try Data(contentsOf: URL(string: urlString)!) 
     if let image = UIImage(data: data) { 
      try data.write(to: fileURL) 
      DispatchQueue.main.async { 
       self.imageView?.image = image 
      } 
     } 
    } catch { 
     print(error) 
    } 
} 

और भी बेहतर, आप NSURLSession का उपयोग करना चाहिए क्योंकि आप: बस बस पुष्टि करते हैं कि डेटा एक छवि निहित है, लेकिन फिर कि मूल NSData

बारे में इस प्रकार, स्विफ्ट 3 में, तो आप शायद की तरह कुछ करना चाहता हूँ बेहतर समस्याओं का निदान कर सकते हैं, यह रद्द करने योग्य है, आदि (और बहिष्कृत NSURLConnection का उपयोग न करें।) मैं प्रतिक्रिया के statusCode भी देख सकता हूं। उदाहरण के लिए:

func requestImage(_ url: URL, fileURL: URL) { 
    let task = URLSession.shared.dataTask(with: url) { data, response, error in 
     // check for fundamental network issues (e.g. no internet, etc.) 

     guard let data = data, error == nil else { 
      print("dataTask error: \(error?.localizedDescription ?? "Unknown error")") 
      return 
     } 

     // make sure web server returned 200 status code (and not 404 for bad URL or whatever) 

     guard let httpResponse = response as? HTTPURLResponse, 200 ..< 300 ~= httpResponse.statusCode else { 
      print("Error; Text of response = \(String(data: data, encoding: .utf8) ?? "(Cannot display)")") 
      return 
     } 

     // save image and update UI 

     if let image = UIImage(data: data) { 
      do { 
       // add directory if it doesn't exist 

       let directory = fileURL.deletingLastPathComponent() 
       try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) 

       // save file 

       try data.write(to: fileURL, options: .atomic) 
      } catch let fileError { 
       print(fileError) 
      } 

      DispatchQueue.main.async { 
       print("image = \(image)") 
       self.imageView?.image = image 
      } 
     } 
    } 
    task.resume() 

} 

नोट, फ़ोल्डर की केवल समय-समय पर निर्माण केवल तभी जरूरी है जब आपने इसे पहले से नहीं बनाया है। निजी तौर पर, जब मैं मूल पथ बनाता हूं, तो मैं पूरा करने वाले हैंडलर के बजाय वहां फ़ोल्डर बनाउंगा, लेकिन आप इसे वैसे भी कर सकते हैं। बस फ़ाइल लिखने से पहले फ़ोल्डर सुनिश्चित करें कि फ़ोल्डर मौजूद है।

भले ही यह मुख्य बिंदुओं को दिखाता है, अर्थात् आपको मूल संपत्ति को सहेजना चाहिए और आपको पृष्ठभूमि में यह करना चाहिए।

स्विफ्ट 2 प्रस्तुतियों के लिए, previous revision of this answer देखें।

+0

मैंने अभी कोशिश की लेकिन किसी भी दूरस्थ या स्थानीय छवि को लोड नहीं किया जा सका। – bilmiyore

+1

@bilmiyore FYI, मैंने कुछ भी गलत होने पर, क्या गलत हो रहा है, इसका निदान करने के लिए त्रुटि प्रबंधन में सुधार करने के लिए मेरा जवाब संशोधित किया। स्थानीय छवि लोडिंग के संदर्भ में, मैंने इसे स्पर्श नहीं किया। – Rob

+0

धन्यवाद @Rob, यह भी काम किया। केवल एक समस्या है जिसे मैं उपनिर्देशिकाओं के साथ काम नहीं कर सकता। "\ (id) -logo.jpg" पथ काम कर रहा है लेकिन "\ (id) \ logo.jpg" नहीं है। – bilmiyore

संबंधित मुद्दे