【问题标题】:Error EXC_BAD_INSTRUCTION while running swift code with NSURL使用 NSURL 运行 swift 代码时出现错误 EXC_BAD_INSTRUCTION
【发布时间】:2015-02-27 22:57:07
【问题描述】:

因此,我构建了一个应用程序,该应用程序从 iTunes 商店加载数据,以显示包含艺术家姓名、歌曲名称和专辑名称的搜索结果。我使用 JSON 完成了这项工作,该应用程序在我添加的搜索栏首次运行时运行良好。我在导航栏中有一个UITextField,将searchTerm 命名为@IBOutlet,该按钮是一个@IBAction 函数,它从searchTerm 生成一个字符串,然后从iTunes Store 获取数据。我很好地加载了应用程序,它构建成功,并且第一次搜索有效。例如,如果我搜索 AC/DC,则会加载:http://imgur.com/mipnLWr。如果我再次尝试搜索,我会得到:http://imgur.com/hDqrcHm,应用程序因之前的结果而冻结,并且控制台中出现此错误:

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

在我的SongsTableViewController 子类UITableViewController 中出现此错误:

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

这是我的 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

    }


}

还有我的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
    }

}

我的歌曲课:

import Foundation

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

和 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>

我知道解开 nil 不好,但是为什么解开 nil 呢? nil 出现在带有let task = session.dataTaskWithURL(url!, completionHandler: {SongsTableViewController 行上,其中url 是已解包的内容,为nil

【问题讨论】:

    标签: ios iphone xcode swift


    【解决方案1】:

    当您搜索名称中包含空格的歌曲时,您的应用程序崩溃的原因是,这会导致网址无效。要构建 URL,您需要进行适当的转义。如果你不这样做,那么NSURL(string: ...) 将返回 nil。

    您实际上并没有检查 url 是否有效(不是 nil),因此您的应用会在您尝试使用它时立即崩溃。

    理想情况下,您真正​​应该做的是使用 NSURLComponents 来构造 URL。它将采用基本 URL、路径和查询参数,并将所有内容组合在一起作为有效的 NSURL 实例,进行所有正确的编码和转义。

    如果您创建一个封装该逻辑的函数,那么您可以执行以下操作:

    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
    }
    

    【讨论】:

    • 我很好奇为什么我被否决了。标记为正确的答案实际上是不正确且不完整的。
    • @DownVoter 这个答案很好。
    【解决方案2】:

    不要使用

    url!
    

    改为使用

    if let url = url {
    }
    

    确保它不为零。

    现在,它无法正常工作的原因可能与 nils 无关,而与 NSURL 字符串中的实际数据有关。每次更改时记录它,并尝试在邮递员中使用它。如果它有效 - 你发送的请求是错误的。如果它在邮递员中失败,则它是一个错误的 url。

    查看 NSURLConnection,发送异步请求,错误捕获更容易。

    【讨论】:

    • 非常感谢!我刚刚意识到是 just 搜索字词中带有空格的错误!所以,如果我在搜索中包含 %20,它会加载!我会解决这个问题,如果你没有指出错误的 url,我就不会解决这个问题!
    • 太棒了 :) 如果有帮助,请接受我的回答!星期五快乐!
    • 这是错误的建议。应该是if let url = url {
    • 我会在 6 分钟内接受!我会给你积分,但我没有足够的! (提示)
    • 另外,不要在搜索中包含 %20,请查看 NSString *formattedUrl =[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 2012-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多