[英]Error EXC_BAD_INSTRUCTION while running swift code with NSURL
因此,我构建了一个应用程序,可以从iTunes商店加载数据,以显示包含艺术家姓名,歌曲名称和专辑名称的搜索结果。 我使用JSON做到了这一点,并且应用程序在我添加的搜索栏的第一次运行时工作正常。 我在导航栏中有一个UITextField
,名为@IBOutlet
,名为@IBOutlet
,该按钮是一个@IBAction
函数,它从@IBAction
一个字符串,然后从iTunes Store中获取数据。 我加载应用程序很好,它构建成功,第一次搜索工作。 例如,如果我搜索AC / DC,则会加载: http : //imgur.com/mipnLWr 。 如果我再次尝试搜索,我会得到这个: http : //imgur.com/hDqrcHm ,该应用程序冻结了以前的结果,并且在控制台中出现此错误:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
和我在UITableViewController
SongsTableViewController
子类中的错误:
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>
我知道解开零是坏事,但为什么要解开零呢? SongsTableViewController
发生在SongsTableViewController
行上, let task = session.dataTaskWithURL(url!, completionHandler: {
,其中url
是已经解包的并且是nil
当您搜索名称中包含空格的歌曲时,您的应用崩溃的原因是因为这会导致无效的网址。 要构建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
}
不要用
url!
改为使用
if let url = url {
}
确保它不是零。
现在,它不起作用的原因可能是nils,而NSURL的字符串中的实际数据更多。 每次更改时记录它,并尝试在邮递员中使用它。 如果它有效 - 您发送的请求是错误的。 如果它在邮递员中失败,那就是一个糟糕的网址。
查看NSURLConnection,发送异步请求,它使错误捕获更容易。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.