24050


swiftにてGracenoteのAPI実装をやっているのですがエラーになってしまいうまく起動することができません。

知識が浅いため一人で解決することができずこちらに質問させていただきました。どう改善すればいいのでしょうか、お力貸していただけると幸いです。

以下がコードです。

具体的には「//requestを送信」の部分が

> Cannot convert value of type '(NSURLResponse!, data: NSData!, error:  
>  NSError!) -> ()' to expected argument type '(NSURLResponse?, NSData?,  
>  NSError?) -> Void'

とエラー表示されてしまい、  
「//取得したXMLをエレメント毎に取得」の部分が

> Objective-C method  
>  'parser:didStartElement:namespaceURI:qualifiedName:attributes:'  
>  provided by method  
>  'parser( _:didStartElement:namespaceURI:qualifiedName:attributes:)'  
>  conflicts with optional requirement method  
>  'parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)' in  
>  protocol 'NSXMLParserDelegate'

とエラー表示されてしまいます。

「XXXXXXXXXXX」の部分にはクライアントIDやユーザーIDが入ります。

よろしくお願いいたします。

[code]

    import UIKit
    
    class ViewController: UIViewController ,NSXMLParserDelegate{
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //XML
            let str = "<QUERIES><AUTH><CLIENT>XXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</CLIENT><USER>XXXXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</USER></AUTH><QUERY CMD='ALBUM_SEARCH'><MODE>SINGLE_BEST_COVER</MODE><TEXT TYPE='ARTIST'>perfume</TEXT><TEXT TYPE='ALBUM_TITLE'>GAME</TEXT><TEXT TYPE='TRACK_TITLE'>チョコレイト・ディスコ</TEXT><OPTION><PARAMETER>SELECT_EXTENDED</PARAMETER><VALUE>COVER,REVIEW,ARTIST_BIOGRAPHY,ARTIST_IMAGE,ARTIST_OET,MOOD,TEMPO</VALUE></OPTION><OPTION><PARAMETER>SELECT_DETAIL</PARAMETER><VALUE>GENRE:3LEVEL,MOOD:2LEVEL,TEMPO:3LEVEL,ARTIST_ORIGIN:4LEVEL,ARTIST_ERA:2LEVEL,ARTIST_TYPE:2LEVEL</VALUE></OPTION></QUERY></QUERIES>"
    
            //UTF-8にエンコード
            let xmlData = str.dataUsingEncoding(NSUTF8StringEncoding)
    
            //URLの指定
            var url: NSURL! = NSURL(string: "https://c9767936.web.cddbp.net/webapi/xml/1.0/")
            var request = NSMutableURLRequest(URL: url)
    
            //XMLヘッダーの指定
            request.setValue("application/xml", forHTTPHeaderField: "Content-type")
    
            //POSTを指定
            request.HTTPMethod = "POST"
    
            //Dataをセット
            request.HTTPBody = xmlData
    
            //requestを送信
            NSURLConnection.sendAsynchronousRequest(request,queue: NSOperationQueue.mainQueue(),completionHandler: response)
    
        }
    
        //返ってきたAPIのデータを取得
        func response(res: NSURLResponse!, data: NSData!, error: NSError!){
    
            //XMLに変換
            let parser : NSXMLParser? = NSXMLParser(data: data)
            if parser != nil {
                parser!.delegate = self
                parser!.parse()
            } else {
                // パースに失敗した時
                print("failed to parse XML")
            }
    
        }
    
        //取得したXMLをエレメント毎に取得
        func parser(parser: NSXMLParser,didStartElement elementName: String,namespaceURI: String?,qualifiedName: String?,attributes attributeDict: [NSObject : AnyObject])
        {
            print(elementName)
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }
    
[/code]


CC BY-SA 3.0
2016-04-15T10:44:29.140
24047
2016-10-14T18:50:38.157
2016-04-15T12:30:32.183
3054
15175
question
swift swift2
swiftでのAPI実装について


_「//requestを送信」の部分_  
かなり古いSwiftの書き方ですね。提示されたエラー(エラー発生の原因は「//返ってきたAPIのデータを取得」の部分の`response(_:data:error:)`メソッドの引数型が間違っているせいです)を修正しても良いのですが、使用している`NSURLConnection`の`sendAsynchronousRequest(_:queue:completionHandler:)`メソッドはiOS9でdeprecated(廃止予定)とされているので、今から作られるアプリでしたらAppleご推薦の`NSURLSession`を使われた方が良いのではないかと思います。

また、完了ハンドラーを別メソッドとしてしまうと、また似たような型の不一致が発生する可能性があります。クロージャーの引数型の決定はSwiftの型推論に任せてしまいましょう。そのためには`response`メソッドに書かれている処理をクロージャー式に変換することになります。

元のコードの:

[code]

        NSURLConnection.sendAsynchronousRequest(request,queue: NSOperationQueue.mainQueue(),completionHandler: response)
    
[/code]

の行を:

[code]

        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(request) {data, response, error in
            //返ってきたAPIのデータを取得
            if let data = data {
                //XMLに変換
                let parser = NSXMLParser(data: data)
                parser.delegate = self
                parser.parse()
                //NSXMLParserのエラーチェックはparse()メソッドを呼んだ後
                if let error = parser.parserError {
                    // パースに失敗した時
                    print("failed to parse XML: \(error)")
                }
            } else {
                //dataがnilの場合(普通は通信エラー)の処理
                //...
            }
        }
        task.resume()
    
[/code]

…なんて形に置き換えてみてください。(`response`メソッドの内容を取り込んだ形ですので、そちらは不要になります。)

* * *

_「//取得したXMLをエレメント毎に取得」の部分_  
こちらも、かなり前にデータ型が変更されているメソッドをずいぶん古い書き方で使用しているようです。  
この辺りの長ったらしいメソッドのヘッダ部を正しく書きたい時は、Xcodeのコード補完機能をうまくつかいましょう。  
(Xcode7.3を想定しています。)  
Xcodeが正しく動いていれば`func`の直前の空行のところで`parserdidstarte`と入力してやればコード補完機能のpopUpに次のような内容が表示されるはずです。

[code]

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, ...
    
[/code]

そのままその候補を選択してやると、次のようなコードがエディターに挿入されます。

[code]

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        <#code#>
    }
    
[/code]

あなたのコードとは`attributes:`パラメータ(`attributeDict`)のデータ型が異なっていることがわかるでしょうか。

Swiftは発展途上の言語で、Objective-
Cで書かれたクラスやプロトコルをSwift側にimportする動作もバージョンにより細部が変わって行っています。正直全ての変化を追うのはかなり大変なことなので、Xcodeのサポート機能をうまく使うようにしてください。

わかりにくい点もあるかと思いますが、この回答に直接関係のある内容はコメント等でお知らせください。(XMLの解析をちゃんと書こうとしたら…的な直接この質問に関係ない場合は、新たに質問スレを立ててください。)


CC BY-SA 3.0
2016-04-15T11:52:01.310
24050
2016-04-15T11:52:01.310
13972
24047
answer