简体   繁体   English

使用NSURL运行swift代码时出错EXC_BAD_INSTRUCTION

[英]Error EXC_BAD_INSTRUCTION while running swift code with NSURL

So, I have built an app that loads data from the iTunes store to display search results with Artist name, song name, and album name. 因此,我构建了一个应用程序,可以从iTunes商店加载数据,以显示包含艺术家姓名,歌曲名称和专辑名称的搜索结果。 I did this using JSON, and the app works fine on the first run with the search bar I added. 我使用JSON做到了这一点,并且应用程序在我添加的搜索栏的第一次运行时工作正常。 I have a UITextField in the nav bar, named searchTerm as an @IBOutlet , the button is an @IBAction function that makes a string from the searchTerm and then fetches the data from the iTunes Store. 我在导航栏中有一个UITextField ,名为@IBOutlet ,名为@IBOutlet ,该按钮是一个@IBAction函数,它从@IBAction一个字符串,然后从iTunes Store中获取数据。 I load the app fine, it builds successfully, and the first search works. 我加载应用程序很好,它构建成功,第一次搜索工作。 For example, if I search AC/DC, this loads: http://imgur.com/mipnLWr . 例如,如果我搜索AC / DC,则会加载: http//imgur.com/mipnLWr If I try to search again, I get this: http://imgur.com/hDqrcHm , the app frozen with the previous results, and this error in the console: 如果我再次尝试搜索,我会得到这个: http//imgur.com/hDqrcHm ,该应用程序冻结了以前的结果,并且在控制台中出现此错误:

fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb) 

and this error in my SongsTableViewController subclass of UITableViewController : 和我在UITableViewController SongsTableViewController子类中的错误:

Thread 1: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0)

Here is my SongsTableViewController class: 这是我的SongsTableViewController类:

import UIKit

class SongsTableViewController: UITableViewController {
    var theSearch = ""
    @IBOutlet weak var searchTerm: UITextField!
    @IBAction func search(sender: AnyObject) {
        theSearch = "\(searchTerm.text)"
        println("searched")
        self.fetchData()
    }
    var songs = [Song]()
    private let cache = NSCache()
    private func fetchData() {
        let url = NSURL(string: "http://itunes.apple.com/search?term=\(theSearch)&country=us")
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithURL(url!, completionHandler: {
            data, response, error in
            if let taskError = error {
                //handle error
            }
            else {
                let httpResponse = response as NSHTTPURLResponse
                switch httpResponse.statusCode {
                case 200:
                    println("got 200")
                    self.parseJson(data)
                default:
                    println("request failed: \(httpResponse.statusCode)")
                }
            }
        })
        task.resume()
    }

    func parseJson(data: NSData) {
        var error: NSError?
        let json : AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments, error: &error)
        if error == nil {
            if let unwrappedJson: AnyObject = json {
                parseSongs(json: unwrappedJson)
            }
        }
    }
    private func parseSongs(#json: AnyObject) {
        songs = []
        if let array = json["results"] as? [[String : AnyObject]] {
            for songDictionary in array {
                if let title = songDictionary["trackName"] as? NSString {
                    if let artist = songDictionary["artistName"] as? NSString {
                        if let albumName = songDictionary["collectionName"] as? NSString {
                            if let artworkUrl = songDictionary["artworkUrl100"] as? NSString {
                                let song = Song(title: title, artist: artist, albumName: albumName, artworkUrl: artworkUrl)
                                songs.append(song)
                            }
                        }
                    }
                }
            }
            dispatch_async(dispatch_get_main_queue()) {
                self.tableView.reloadData()
            }
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    }

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

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Potentially incomplete method implementation.
        // Return the number of sections.
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete method implementation.
        // Return the number of rows in the section.
        return songs.count
    }

    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "\(theSearch) Songs"
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        let song = songs[indexPath.row]
        cell.textLabel?.text = song.title
        cell.detailTextLabel?.text = song.albumName
        if let image = cache.objectForKey(song.artworkUrl) as? UIImage {
                cell.imageView?.image = image
        }
        else {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
                let data = NSData(contentsOfURL: NSURL(string: song.artworkUrl)!)
                let image = UIImage(data: data!)
                self.cache.setObject(image!, forKey: song.artworkUrl)
                dispatch_async(dispatch_get_main_queue()) {
                    self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
                }
            }
        }
        return cell
    }

    /*
    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return NO if you do not want the specified item to be editable.
        return true
    }
    */

    /*
    // Override to support editing the table view.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            // Delete the row from the data source
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        } else if editingStyle == .Insert {
            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
        }    
    }
    */

    /*
    // Override to support rearranging the table view.
    override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {

    }
    */

    /*
    // Override to support conditional rearranging of the table view.
    override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return NO if you do not want the item to be re-orderable.
        return true
    }
    */


    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
        let detailViewController = segue.destinationViewController as SongDetailViewController
        let cell = sender as UITableViewCell
        let indexPath = tableView.indexPathForCell(cell)!
        let song = songs[indexPath.row]
        detailViewController.song = song

    }


}

and my SongsDetailViewController : 和我的SongsDetailViewController

import UIKit

class SongDetailViewController: UIViewController {
    var song: Song?;
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var artistLabel: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.updateView();
        // Do any additional setup after loading the view.
    }
    func updateView() {
        println("Code Monkey");
        titleLabel.text = song?.title
        artistLabel.text = song?.artist
    }

}

my Song class: 我的歌班:

import Foundation

struct Song {
    var title: String;
    var artist: String;
    let albumName: String = "";
    let artworkUrl: String = "";
}

and the Main.storyboard as xml: 和Main.storyboard为xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14A361p" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="J4e-4J-Qag">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
    </dependencies>
    <scenes>
        <!--Songs Table View Controller-->
        <scene sceneID="o2z-qw-46Z">
            <objects>
                <tableViewController id="7pZ-HZ-fPi" customClass="SongsTableViewController" customModule="Songs" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="usS-1O-Bb9">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <prototypes>
                            <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="KyS-jU-iVa" detailTextLabel="v39-NZ-fKp" style="IBUITableViewCellStyleSubtitle" id="Dxe-az-DTs">
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Dxe-az-DTs" id="s0z-IA-UE6">
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="KyS-jU-iVa">
                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
                                            <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                        <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="v39-NZ-fKp">
                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="11"/>
                                            <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                    </subviews>
                                </tableViewCellContentView>
                                <connections>
                                    <segue destination="IaK-66-iRk" kind="show" identifier="showSongDetails" id="Qvk-MK-NHw"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="7pZ-HZ-fPi" id="1Fa-g3-eTG"/>
                            <outlet property="delegate" destination="7pZ-HZ-fPi" id="F2P-n2-c00"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="DSQ-mu-WTl">
                        <nil key="title"/>
                        <textField key="titleView" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" minimumFontSize="17" id="OyO-T3-pkK" userLabel="Search">
                            <rect key="frame" x="180" y="7" width="240" height="30"/>
                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
                            <textInputTraits key="textInputTraits"/>
                        </textField>
                        <barButtonItem key="rightBarButtonItem" style="plain" id="fPc-Nn-AF7">
                            <button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="hzA-Ku-WOK">
                                <rect key="frame" x="-23" y="-15" width="133" height="30"/>
                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                <state key="normal" title="Go">
                                    <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
                                </state>
                                <connections>
                                    <action selector="search:" destination="7pZ-HZ-fPi" eventType="touchUpInside" id="9ny-cc-B47"/>
                                </connections>
                            </button>
                            <connections>
                                <action selector="search" destination="7pZ-HZ-fPi" id="Mav-7f-Nw9"/>
                            </connections>
                        </barButtonItem>
                    </navigationItem>
                    <connections>
                        <outlet property="searchTerm" destination="OyO-T3-pkK" id="LGU-GM-rOh"/>
                    </connections>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="pBf-2K-Quz" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1091" y="421"/>
        </scene>
        <!--Song Detail View Controller-->
        <scene sceneID="EY0-P9-lxp">
            <objects>
                <viewController id="IaK-66-iRk" customClass="SongDetailViewController" customModule="Songs" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="NcC-3p-PzZ"/>
                        <viewControllerLayoutGuide type="bottom" id="v8u-7K-8VY"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Gag-Xd-hMv">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="neB-pw-mZC">
                                <rect key="frame" x="115" y="216" width="42" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aXT-AM-FSZ">
                                <rect key="frame" x="115" y="289" width="42" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="neB-pw-mZC" firstAttribute="top" secondItem="NcC-3p-PzZ" secondAttribute="bottom" constant="154" id="PwZ-wP-g5X"/>
                            <constraint firstItem="aXT-AM-FSZ" firstAttribute="centerX" secondItem="neB-pw-mZC" secondAttribute="centerX" constant="3" id="SJa-en-Fsl"/>
                            <constraint firstItem="aXT-AM-FSZ" firstAttribute="top" secondItem="neB-pw-mZC" secondAttribute="bottom" constant="50" id="qCi-A1-mRH"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="artistLabel" destination="aXT-AM-FSZ" id="3tP-9I-8KR"/>
                        <outlet property="titleLabel" destination="neB-pw-mZC" id="kBk-Wt-IOE"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="nNS-Sx-Qsb" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1943" y="411"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="d4l-Tj-sHo">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="J4e-4J-Qag" sceneMemberID="viewController">
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="JSx-T8-Kzc">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="7pZ-HZ-fPi" kind="relationship" relationship="rootViewController" id="iec-gq-WSz"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="ho4-Dh-fvD" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="279" y="421"/>
        </scene>
    </scenes>
</document>

I know that unwrapping nil is bad, but why does it unwrap nil? 我知道解开零是坏事,但为什么要解开零呢? The nil occurs on the SongsTableViewController line with let task = session.dataTaskWithURL(url!, completionHandler: { , where url is what has been unwrapped and is nil SongsTableViewController发生在SongsTableViewController行上, let task = session.dataTaskWithURL(url!, completionHandler: { ,其中url是已经解包的并且是nil

The reason your app crashes when you search for songs with a space in the name is because that results in an invalid url. 当您搜索名称中包含空格的歌曲时,您的应用崩溃的原因是因为这会导致无效的网址。 To build an URL you need to do proper escaping. 要构建URL,您需要进行适当的转义。 If you don't then NSURL(string: ...) will return nil. 如果不这样,那么NSURL(string: ...)将返回nil。

You don't actually check if url is valid (not nil), so your app crashes as soon as you try to use it. 您实际上并未检查url是否有效(不是nil),因此一旦您尝试使用它,您的应用就会崩溃。

Ideally what you should really do is use NSURLComponents to construct the URL. 理想情况下,您应该使用NSURLComponents构建URL。 It will take a base URL, path and query arguments and mangle everything together as a valid NSURL instance, doing all the proper encoding and escaping. 它将采用基本URL,路径和查询参数,并将所有内容组合在一起作为有效的NSURL实例,执行所有正确的编码和转义。

If you create a function that encapsulates that logic then you can do something as follows: 如果您创建一个封装该逻辑的函数,那么您可以执行以下操作:

private func fetchData() {
    if let url = searchURLWithTerm("Foo Fighters") {
        ... rest of your code here ...
    }
}

func searchURLWithTerm(term: String) -> NSURL? {
    if let components = NSURLComponents(string: "http://itunes.apple.com/search") {
        components.queryItems = [NSURLQueryItem(name: "country", value: "US"),
            NSURLQueryItem(name: "term", value: term)]
        return components.URL
    }
    return nil
}

Don't use 不要用

url!

instead use 改为使用

if let url = url {
}

To make sure that it is not nil. 确保它不是零。

Now, the reason it not working is probably less with the nils, and more with the actual data in the string for NSURL. 现在,它不起作用的原因可能是nils,而NSURL的字符串中的实际数据更多。 Log it every time it changes, and try to use it in postman. 每次更改时记录它,并尝试在邮递员中使用它。 If it works - you are sending the request wrong. 如果它有效 - 您发送的请求是错误的。 If it fails in postman, its a bad url. 如果它在邮递员中失败,那就是一个糟糕的网址。

Look into NSURLConnection, send asynchronous request, it makes error catching much easier. 查看NSURLConnection,发送异步请求,它使错误捕获更容易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM