XML 数据保存在 NSUserDefaults 或文档目录中
XML data save in NSUserDefaults or in Documents Directory
我正在制作一个简单的新闻应用程序,并尝试在 NSUserDefaults 中保存(标题、描述、日期、图像及其数据)以供离线阅读。我希望当它在 NSUserDefaults 中保存数据时,它会离线显示,并且当有新数据可用时,它会重写或替换为以前的数据。
我知道如何在 NSUserDefaults 中保存字符串数组,但不知道如何在 NSUserDefaults 中保存图像。我正在尝试制定保存数据的逻辑并检查它是否有新数据可用但没有成功,启动画面也需要更多时间才能消失,这是由于从服务器加载数据还是由于互联网连接速度慢?
任何人都可以检查我的代码以修复它。
谢谢
class ViewController2: UIViewController ,NSXMLParserDelegate {
let newsDefaults = NSUserDefaults.standardUserDefaults()
@IBOutlet weak var tableView: UITableView!
var parser = NSXMLParser()
var posts = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var title1 = NSMutableString()
var date = NSMutableString()
var link = NSMutableString()
var des = NSMutableString()
var img2 = NSMutableString()
var NSUserDefaultsTitle : [NSString] = []
var NSUserDefaultsDate : [NSString] = []
var NSUserDefaultsDes : [NSString] = []
var NSUserDefaultsImage : [UIImage] = []
typealias CompletionHandler = (image: UIImage) -> Void
var attrsUrl : [String : NSString]!
var urlPic : NSString?
var postLink: String = String()
override func viewDidLoad() {
super.viewDidLoad()
self.configure()
self.beginParsing()
}
override func viewWillAppear(animated: Bool) {
// if let HaveTitle = newsDefaults.objectForKey("t"){
// NSUserDefaultsTitle = HaveTitle.mutableCopy() as! [NSString]
// }
// if let HaveDate = newsDefaults.objectForKey("d"){
// NSUserDefaultsDate = HaveDate.mutableCopy() as! [NSString]
// }
// if let HaveDes = newsDefaults.objectForKey("des"){
// NSUserDefaultsDes = HaveDes.mutableCopy() as! [NSString]
// }
// if let imageData = newsDefaults.objectForKey("imgData"){
// NSUserDefaultsImage = imageData.mutableCopy() as! [UIImage]
// }
//
// print(newsDefaults.objectForKey("d"))
}
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string: "http://www.voanews.com/api/zq$omekvi_"))!)!
parser.delegate = self
parser.parse()
tableView!.reloadData()
}
//XMLParser Methods
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String])
{
element = elementName
if (elementName as NSString).isEqualToString("item")
{
elements = NSMutableDictionary()
elements = [:]
title1 = NSMutableString()
title1 = ""
date = NSMutableString()
date = ""
link = NSMutableString()
link = ""
des = NSMutableString()
des = ""
img2 = NSMutableString()
img2 = ""
}
if elementName == "enclosure" {
attrsUrl = attributeDict as [String: NSString]
urlPic = attrsUrl["url"]
print(urlPic!, terminator: "")
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
if (elementName as NSString).isEqualToString("item") {
if !title1.isEqual(nil) {
elements.setObject(title1, forKey: "title")
}
if !date.isEqual(nil) {
elements.setObject(date, forKey: "pubDate")
}
if !link.isEqual(nil) {
elements.setObject(link, forKey: "link")
}
if !des.isEqual(nil){
elements.setObject(des, forKey: "description")
}
if !img2.isEqual(nil){
elements.setObject(urlPic!, forKey: "enclosure")
}
posts.addObject(elements)
//
// if let HaveData = newsDefaults.objectForKey("post"){
//
// }else{
//
//// newsDefaults.setObject(self.posts.valueForKey("title"), forKey: "t")
//// newsDefaults.setObject(self.posts.valueForKey("pubDate"), forKey: "d")
//// newsDefaults.setObject(self.posts.valueForKey("description"), forKey: "des")
//
// newsDefaults.setObject(posts, forKey: "post")
//
print("elementName")
// }
}
print("didEndElement")
}
func parser(parser: NSXMLParser, foundCharacters string: String)
{
if element.isEqualToString("title") {
title1.appendString(string)
} else if element.isEqualToString("pubDate") {
date.appendString(string)
print(date)
}
else if element.isEqualToString("link"){
link.appendString(string)
}else if element.isEqualToString("description"){
des.appendString(string)
}else if element.isEqualToString("enclosure"){
img2.appendString(string)
}
print("foundCharacter")
}
private func configure() {
self.navigationController?.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(20.0), NSForegroundColorAttributeName: UIColor.whiteColor()]
self.tableView.registerNib(UINib(nibName: "2ImageCell", bundle: nil), forCellReuseIdentifier: "imageCell")
self.tableView.delegate = self
self.tableView.dataSource = self
self.fillNavigationBar(color: UIColor(red: 252.0/255.0, green: 0, blue: 0, alpha: 1.0))
}
private func fillNavigationBar(color color: UIColor) {
if let nav = self.navigationController {
nav.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
nav.navigationBar.shadowImage = UIImage()
for view in nav.navigationBar.subviews {
if view.isKindOfClass(NSClassFromString("_UINavigationBarBackground")!) {
if view.isKindOfClass(UIView) {
(view as UIView).backgroundColor = color
}
}
}
}
}
}
extension ViewController2: UITableViewDelegate, UITableViewDataSource {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
let view = ImageModalView2.instantiateFromNib()
view.des.text = posts.objectAtIndex(indexPath.row).valueForKey("description") as? String
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
view.image = img
})
})
let window = UIApplication.sharedApplication().delegate?.window!
let modal = PathDynamicModal.show(modalView: view, inView: window!)
view.closeButtonHandler = {[weak modal] in
modal?.closeWithLeansRandom()
return
}
}
@IBAction func printData(sender: AnyObject) {
print(NSUserDefaultsImage)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80.0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("imageCell", forIndexPath: indexPath) as! ImageCell2
// if let picURL = user["picture"].string, url = NSURL(string: picURL) {
// if let data = NSData(contentsOfURL: url) {
// cell!.imageView?.image = UIImage(data: data)
// }
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
// if NSUserDefaultsImage {
// cell.sideImageView.image = NSUserDefaultsImage[indexPath.row]
// }else{
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
cell.sideImageView.image = img
// self.NSUserDefaultsImage.append(img)
// print(img)
// self.newsDefaults.setObject(self.NSUserDefaultsImage, forKey: "imgData")
})
})
// }
//cell.date.text = posts.objectAtIndex(indexPath.row).valueForKey("pubDate") as? String
//cell.sideImageView?.contentMode = UIViewContentMode.ScaleAspectFit
//cell.sideImageView?.image = image
cell.titleLabel.userInteractionEnabled = false
cell.titleLabel.editable = false
cell.titleLabel.selectable = false
return cell
}
func downloadFileFromURL(url1: NSURL?,completionHandler: CompletionHandler) {
// download code.
if let url = url1{
let priority = DISPATCH_QUEUE_PRIORITY_HIGH
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let data = NSData(contentsOfURL: url)
if data != nil {
print("image downloaded")
completionHandler(image: UIImage(data: data!)!)
}
}
}
}
}
Apple 不推荐在 NSUserDefault 中保存大数据,我们不应该保存大数据。 NSUserDefault 或 Keychain 我们用来存储 "Username"、"Password" 之类的信息较少。
为了将图像保存到 NSUserDefaults,您需要将其转换为 NSData,因为那里只允许某些类型。
至于在其中存储信息以供离线查看的想法....这听起来更像是应用程序文档目录的工作。您应该能够在对象中使用 NSCoding 协议,并通过调用将所有信息写入磁盘
NSKeyedArchiver:archiveRootObject:toFile 在主对象上,它将在所有子对象上调用 encodeWithCoder。
我正在制作一个简单的新闻应用程序,并尝试在 NSUserDefaults 中保存(标题、描述、日期、图像及其数据)以供离线阅读。我希望当它在 NSUserDefaults 中保存数据时,它会离线显示,并且当有新数据可用时,它会重写或替换为以前的数据。 我知道如何在 NSUserDefaults 中保存字符串数组,但不知道如何在 NSUserDefaults 中保存图像。我正在尝试制定保存数据的逻辑并检查它是否有新数据可用但没有成功,启动画面也需要更多时间才能消失,这是由于从服务器加载数据还是由于互联网连接速度慢? 任何人都可以检查我的代码以修复它。 谢谢
class ViewController2: UIViewController ,NSXMLParserDelegate {
let newsDefaults = NSUserDefaults.standardUserDefaults()
@IBOutlet weak var tableView: UITableView!
var parser = NSXMLParser()
var posts = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var title1 = NSMutableString()
var date = NSMutableString()
var link = NSMutableString()
var des = NSMutableString()
var img2 = NSMutableString()
var NSUserDefaultsTitle : [NSString] = []
var NSUserDefaultsDate : [NSString] = []
var NSUserDefaultsDes : [NSString] = []
var NSUserDefaultsImage : [UIImage] = []
typealias CompletionHandler = (image: UIImage) -> Void
var attrsUrl : [String : NSString]!
var urlPic : NSString?
var postLink: String = String()
override func viewDidLoad() {
super.viewDidLoad()
self.configure()
self.beginParsing()
}
override func viewWillAppear(animated: Bool) {
// if let HaveTitle = newsDefaults.objectForKey("t"){
// NSUserDefaultsTitle = HaveTitle.mutableCopy() as! [NSString]
// }
// if let HaveDate = newsDefaults.objectForKey("d"){
// NSUserDefaultsDate = HaveDate.mutableCopy() as! [NSString]
// }
// if let HaveDes = newsDefaults.objectForKey("des"){
// NSUserDefaultsDes = HaveDes.mutableCopy() as! [NSString]
// }
// if let imageData = newsDefaults.objectForKey("imgData"){
// NSUserDefaultsImage = imageData.mutableCopy() as! [UIImage]
// }
//
// print(newsDefaults.objectForKey("d"))
}
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string: "http://www.voanews.com/api/zq$omekvi_"))!)!
parser.delegate = self
parser.parse()
tableView!.reloadData()
}
//XMLParser Methods
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String])
{
element = elementName
if (elementName as NSString).isEqualToString("item")
{
elements = NSMutableDictionary()
elements = [:]
title1 = NSMutableString()
title1 = ""
date = NSMutableString()
date = ""
link = NSMutableString()
link = ""
des = NSMutableString()
des = ""
img2 = NSMutableString()
img2 = ""
}
if elementName == "enclosure" {
attrsUrl = attributeDict as [String: NSString]
urlPic = attrsUrl["url"]
print(urlPic!, terminator: "")
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
if (elementName as NSString).isEqualToString("item") {
if !title1.isEqual(nil) {
elements.setObject(title1, forKey: "title")
}
if !date.isEqual(nil) {
elements.setObject(date, forKey: "pubDate")
}
if !link.isEqual(nil) {
elements.setObject(link, forKey: "link")
}
if !des.isEqual(nil){
elements.setObject(des, forKey: "description")
}
if !img2.isEqual(nil){
elements.setObject(urlPic!, forKey: "enclosure")
}
posts.addObject(elements)
//
// if let HaveData = newsDefaults.objectForKey("post"){
//
// }else{
//
//// newsDefaults.setObject(self.posts.valueForKey("title"), forKey: "t")
//// newsDefaults.setObject(self.posts.valueForKey("pubDate"), forKey: "d")
//// newsDefaults.setObject(self.posts.valueForKey("description"), forKey: "des")
//
// newsDefaults.setObject(posts, forKey: "post")
//
print("elementName")
// }
}
print("didEndElement")
}
func parser(parser: NSXMLParser, foundCharacters string: String)
{
if element.isEqualToString("title") {
title1.appendString(string)
} else if element.isEqualToString("pubDate") {
date.appendString(string)
print(date)
}
else if element.isEqualToString("link"){
link.appendString(string)
}else if element.isEqualToString("description"){
des.appendString(string)
}else if element.isEqualToString("enclosure"){
img2.appendString(string)
}
print("foundCharacter")
}
private func configure() {
self.navigationController?.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(20.0), NSForegroundColorAttributeName: UIColor.whiteColor()]
self.tableView.registerNib(UINib(nibName: "2ImageCell", bundle: nil), forCellReuseIdentifier: "imageCell")
self.tableView.delegate = self
self.tableView.dataSource = self
self.fillNavigationBar(color: UIColor(red: 252.0/255.0, green: 0, blue: 0, alpha: 1.0))
}
private func fillNavigationBar(color color: UIColor) {
if let nav = self.navigationController {
nav.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
nav.navigationBar.shadowImage = UIImage()
for view in nav.navigationBar.subviews {
if view.isKindOfClass(NSClassFromString("_UINavigationBarBackground")!) {
if view.isKindOfClass(UIView) {
(view as UIView).backgroundColor = color
}
}
}
}
}
}
extension ViewController2: UITableViewDelegate, UITableViewDataSource {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
let view = ImageModalView2.instantiateFromNib()
view.des.text = posts.objectAtIndex(indexPath.row).valueForKey("description") as? String
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
view.image = img
})
})
let window = UIApplication.sharedApplication().delegate?.window!
let modal = PathDynamicModal.show(modalView: view, inView: window!)
view.closeButtonHandler = {[weak modal] in
modal?.closeWithLeansRandom()
return
}
}
@IBAction func printData(sender: AnyObject) {
print(NSUserDefaultsImage)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80.0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("imageCell", forIndexPath: indexPath) as! ImageCell2
// if let picURL = user["picture"].string, url = NSURL(string: picURL) {
// if let data = NSData(contentsOfURL: url) {
// cell!.imageView?.image = UIImage(data: data)
// }
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
// if NSUserDefaultsImage {
// cell.sideImageView.image = NSUserDefaultsImage[indexPath.row]
// }else{
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
cell.sideImageView.image = img
// self.NSUserDefaultsImage.append(img)
// print(img)
// self.newsDefaults.setObject(self.NSUserDefaultsImage, forKey: "imgData")
})
})
// }
//cell.date.text = posts.objectAtIndex(indexPath.row).valueForKey("pubDate") as? String
//cell.sideImageView?.contentMode = UIViewContentMode.ScaleAspectFit
//cell.sideImageView?.image = image
cell.titleLabel.userInteractionEnabled = false
cell.titleLabel.editable = false
cell.titleLabel.selectable = false
return cell
}
func downloadFileFromURL(url1: NSURL?,completionHandler: CompletionHandler) {
// download code.
if let url = url1{
let priority = DISPATCH_QUEUE_PRIORITY_HIGH
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let data = NSData(contentsOfURL: url)
if data != nil {
print("image downloaded")
completionHandler(image: UIImage(data: data!)!)
}
}
}
}
}
Apple 不推荐在 NSUserDefault 中保存大数据,我们不应该保存大数据。 NSUserDefault 或 Keychain 我们用来存储 "Username"、"Password" 之类的信息较少。
为了将图像保存到 NSUserDefaults,您需要将其转换为 NSData,因为那里只允许某些类型。
至于在其中存储信息以供离线查看的想法....这听起来更像是应用程序文档目录的工作。您应该能够在对象中使用 NSCoding 协议,并通过调用将所有信息写入磁盘 NSKeyedArchiver:archiveRootObject:toFile 在主对象上,它将在所有子对象上调用 encodeWithCoder。