解包时可以选择Nil

时间:2016-03-03 20:21:44

标签: ios swift xml-parsing

我有一个表视图,可以从RSS提要中获取数据。表视图加载每个元素的标题字符串,但是当我选择一行去转到所选行的url时,由于在解开可选值时意外找到nil,它会崩溃。此外,图像未从图像URL加载。我已经证实这些与印刷声明不一致。我错过了什么?它在let safariVC = SFSafariViewController(URL: url!, entersReaderIfAvailable: true)

上崩溃了

我确信表格视图中的每个项目都会有一个链接,所以强行解包不应该是一个问题。以下是其中一个网址的示例:linkString: http://kyfbnewsroom.com/state-ag-department-assisted-the-farm-community-through-a-month-marked-by-challenges/但网址为零。

这是完整的代码。

import UIKit
import SafariServices

class NewsFeedTableViewController: UITableViewController, NSXMLParserDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate, UINavigationControllerDelegate, SFSafariViewControllerDelegate, APLSlideMenuViewControllerDelegate {

    var urlString = NSString()
    var parser = NSXMLParser()
    var posts = NSMutableArray()
    var elements = NSMutableDictionary()
    var element = NSString()
    var itemTitle = NSMutableString()
    var link = NSMutableString()
    var thumbnailURL = NSMutableString()
    var isActionAlert = false
    var attributes = NSDictionary()
    var connection: NSURLConnection?
    var xmlData: NSMutableData?

    var loadingIndicator = UIActivityIndicatorView()
    var backgroundImage = UIImage()
    var backgroundImageView = UIImageView()
    let kfbBlue = UIColor(red: 8.0 / 255.0, green: 77.0 / 255.0, blue: 139.0 / 255.0, alpha: 0.7)

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.registerNib(UINib(nibName: "NewsCell", bundle: nil), forCellReuseIdentifier: "newsCell")

        let menuButton = UIBarButtonItem(image: UIImage(named: "list_button"), style: .Done, target: self, action: "showMenu")
        self.navigationItem.leftBarButtonItem = menuButton

        let reloadButton = UIBarButtonItem(barButtonSystemItem: .Refresh, target: self, action: "reload")
        self.navigationItem.rightBarButtonItem = reloadButton

        backgroundImageView = UIImageView(image: backgroundImage)
        tableView.backgroundView = backgroundImageView

        let width = CGRectGetWidth(self.view.bounds)
        let height = CGRectGetHeight(self.view.bounds)

        loadingIndicator = UIActivityIndicatorView(frame: CGRectMake(width / 2, height / 2, 75, 75))
        loadingIndicator.layer.cornerRadius = 10
        loadingIndicator.backgroundColor = kfbBlue
        loadingIndicator.center = CGPointMake(width / 2, height / 2 - 37)
        loadingIndicator.activityIndicatorViewStyle = .WhiteLarge
        loadingIndicator.hidesWhenStopped = true
        tableView.addSubview(loadingIndicator)
        loadingIndicator.startAnimating()
    }

    override func viewDidDisappear(animated: Bool) {
        loadingIndicator.stopAnimating()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func showMenu() {
        self.slideMenuController().showLeftMenu(true)
    }

    func beginParsing() {
        posts = []
        xmlData = NSMutableData()
        let url = NSURL(string: self.urlString as String)
        let req = NSURLRequest(URL: url!)
        connection = NSURLConnection(request: req, delegate: self, startImmediately: true)!
    }

    func reload() {
        loadingIndicator.startAnimating()
        self.beginParsing()
    }

    // MARK: - NSURLConnection Methods

    func connection(connection: NSURLConnection, didReceiveData data: NSData) {
        xmlData!.appendData(data)
    }

    func connectionDidFinishLoading(connection: NSURLConnection) {
        loadingIndicator.stopAnimating()

        let effectImage = self.backgroundImage.applyDarkEffect()
        self.backgroundImageView.image = effectImage

        parser = NSXMLParser(data: self.xmlData!)
        parser.delegate = self
        parser.parse()
        xmlData = nil
        tableView.reloadData()
    }

    func connection(connection: NSURLConnection, didFailWithError error: NSError) {
        self.connection = nil
        self.xmlData = nil

        loadingIndicator.stopAnimating()

        let errorString = NSString(format: "Fetch failed: %@", error.localizedDescription)
        TSMessage.showNotificationWithTitle("Network Error", subtitle: errorString as String, type: .Error)
    }

    // MARK: - XML Parser Methods

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {

        attributes = attributeDict

        element = elementName
        if ((elementName as NSString).isEqualToString("item")) {
            elements = NSMutableDictionary()
            elements = [:]
            itemTitle = NSMutableString()
            itemTitle = ""
            link = NSMutableString()
            link = ""
            thumbnailURL = NSMutableString()
            thumbnailURL = ""
        }
    }

    func parser(parser: NSXMLParser, foundCharacters string: String) {
        if (string == "Action Alert") {
            self.isActionAlert = true
        }

        if (element.isEqualToString("title")) {
            itemTitle.appendString(string)
        } else if (element.isEqualToString("link")) {
            link.appendString(string)
        } else if (element.isEqualToString("media:thumbnail")) {
            thumbnailURL.appendString(attributes.objectForKey("url") as! String)
        }
    }

    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if (!isActionAlert) {
            if ((elementName as NSString).isEqualToString("item")) {
                if !itemTitle.isEqual(nil) {
                    elements.setObject(itemTitle, forKey: "title")
                }
                if !link.isEqual(nil) {
                    elements.setObject(link, forKey: "link")
                }
                if !thumbnailURL.isEqual(nil) {
                    elements.setObject(thumbnailURL, forKey: "thumbnail")
                }

                posts.addObject(elements)
            }
        }
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 136
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("newsCell", forIndexPath: indexPath) as! NewsCell

        cell.newsTitle?.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as? String
        cell.newsTitle!.textColor = UIColor.whiteColor()
        if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
            cell.newsTitle!.font = UIFont(name: "FranklinGothicStd-ExtraCond", size: 22.0)
        } else {
            cell.newsTitle!.font = UIFont(name: "FranklinGothicStd-ExtraCond", size: 30.0)
        }
        cell.backgroundColor = UIColor.clearColor()
        cell.selectionStyle = .None

        var thumbString = posts.objectAtIndex(indexPath.row).valueForKey("thumbnail") as? String
    thumbString = thumbString!.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
    thumbString = thumbString!.stringByReplacingOccurrencesOfString("%09%09", withString:"")
    print(String(format: "thumbString: %@", thumbString!))
    // let thumbURL = NSURL(string: (posts.objectAtIndex(indexPath.row).valueForKey("thumbnail") as? String)!)
    let thumbURL = NSURL(string: thumbString!)

        cell.newsThumb?.sd_setImageWithURL(thumbURL, placeholderImage: UIImage(named: "placeholder"))
        cell.newsThumb!.layer.cornerRadius = 45.0
        cell.newsThumb!.clipsToBounds = true
        cell.newsThumb!.layer.borderWidth = 2.0
        cell.newsThumb!.layer.borderColor = UIColor.clearColor().CGColor
        cell.newsThumb!.backgroundColor = UIColor.clearColor()

        print(posts.objectAtIndex(indexPath.row).valueForKey("title"))
        print(posts.objectAtIndex(indexPath.row).valueForKey("link"))
        print(posts.objectAtIndex(indexPath.row).valueForKey("thumbnail"))

        return cell
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let linkString = posts.objectAtIndex(indexPath.row).valueForKey("link") as? String
        let url = NSURL(string: linkString!)
        let safariVC = SFSafariViewController(URL: url!, entersReaderIfAvailable: true)
        safariVC.view.tintColor = kfbBlue
        self.navigationController?.presentViewController(safariVC, animated: true, completion: nil)
    }
}

3 个答案:

答案 0 :(得分:0)

这通常在强制展开可选值时发生:" optionalValue!"

尝试使用if let重写您的方法。 e.g。

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if let linkString = posts.objectAtIndex(indexPath.row).valueForKey("link") as? String, url = NSURL(string: linkString) {
        let safariVC = SFSafariViewController(URL: url, entersReaderIfAvailable: true)
        safariVC.view.tintColor = kfbBlue
        self.navigationController?.presentViewController(safariVC, animated: true, completion: nil)
    }
}

答案 1 :(得分:0)

我有些人提到你试图使用!运算符将强制展开作为可选值。但它发生的地方是有趣的一点。根据{{​​1}} NSURL的构造函数Apple

  

返回使用init(string:)初始化的NSURL对象。如果网址字符串格式错误,请返回URLString

因此,当您尝试调用以下代码时:

nil

由于某些原因,let safariVC = SFSafariViewController(URL: url!, entersReaderIfAvailable: true) url,您需要先使用可选绑定进行检查才能解开可选值,请参阅以下代码:

nil

在上面的代码中,应该更好地检查if let url = NSURL(string: linkString!) { ...do rest of your code here } 的值{strong> optional-binding ,然后再打开它的值,在另一个答案中推荐:

linkString

我希望这对你有所帮助。

答案 2 :(得分:-1)

我通过添加

获得了链接
linkString = linkString!.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
            linkString = linkString?.stringByReplacingOccurrencesOfString("%09%09", withString:"")

即使我使用图片网址执行此操作,我仍然无法显示图像。看起来图像没有加载,因为图像URL被添加到thumbString两次。 thumbString: http://kyfbnewsroom.com/wp-content/uploads/2012/10/farm-to-school-150x120.jpeghttp://kyfbnewsroom.com/wp-content/uploads/2012/10/farm-to-school-150x120.jpeg