何でも一回はやってみよう。

気が向いた事は何でも一回試してるビール大好きなおっさんッス。

ベーシック認証とJSONとUIwebView。

ベーシック認証が設定されているサーバーのJSONを読み込んでやりたかった事。
① 画像までのパスを取得してUIImageに設定したかった。
② UIWebViewに読み込みたいページのURLを取得して表示したかった。

で、、、
JSONに関してはAlamofireを使ってJSONを取得

{
  "responseData": {
    "feed": {
      "entries": [
        {
          "id": "220",
          "title": "タイトルが入ります。",
          "text": "記事の本文です。",
          "cat": "カテゴリー",
          "subCat": "サブカテゴリー",
          "thumbnail": "http://◯◯◯.com/img/entry/☓☓☓.jpg",
          "url": "http://◯◯◯.com/△△△△.html"
        }
      ]
    }
  }
}

というJSONデータを読み込みます。

let user = "userId"
let password = "userPass"

// JSONのパース
func parse(url: String, completion: (([JSON]?, NSError?) -> Void)){
   var url = NSURL(string: url)
   Alamofire.request(.GET, url!, parameters: nil, encoding: .JSON)
      .authenticate(user: user, password: password)
      .responseJSON{ (request, response, data, error) in
         let json = JSON(data!)
         let entries = json["responseData"]["feed"]["entries"].array
            completion(entries, error)
   }
}

.authenticate(user: user, password: password)
と、この一文を足すとベーシック認証下のJSONは読み込めましたが、画像、UIWebViewへの埋め込みはできませんでした。

色々と考えたのですが結局JSONファイルを修正しました。

{
  "responseData": {
    "feed": {
      "entries": [
        {
          "id": "220",
          "title": "タイトルが入ります。",
          "text": "記事の本文です。",
          "cat": "カテゴリー",
          "subCat": "サブカテゴリー",
          "thumbnail": "http://userId:userPass@◯◯◯.com/img/entry/☓☓☓.jpg",
          "url": "http://userId:userPass@◯◯◯.com/△△△△.html"
        }
      ]
    }
  }
}

てな感じで、URLに直接ユーザー名・パスワードを埋め込みました。
(このページを参照)
http://qiita.com/ngkazu/items/6da021edf177f40e1f26

これで無事、表示しました。
開発中のアプリ内のJSONキャッシュは結構きついのでキャッシュ対策をしておく方が無難です。

http://◯◯◯.com/▲▲▲▲▲.json?123

とURLに?〜をつければOK。

SwiftyJSONとAlamofireとTableView。

単純なんですけど、JSONを読み込んでその項目分のセクション、行数を作成するときにハマりました。

import UIKit
import SwiftyJSON
import Alamofire
class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var jsonURLString = "http://◯◯◯◯◯◯.json"
    // セクションのタイトル
    var sectionArray: NSMutableArray = []
    // 各要素
    var itemArray: NSMutableArray = []
    var sectionKosu: Int = Int()
    override func viewDidLoad() {
        super.viewDidLoad()
        // JSONのパース
        Alamofire.request(.GET, jsonURLString, parameters: nil, encoding: .JSON)
            .responseJSON { (request, response, responseData, error) -> Void in
                if let data: AnyObject = responseData {
                    let results = JSON(data)
                    let count: Int = results["responseData"]["feed"]["entries"].count

                    for index in 0..<count {
                        // タイトルの抜き出し
                        let title = results["responseData"]["feed"]["entries"][index]["ttl"].string!
                        self.sectionArray.addObject(title)

                        // セルの項目
                        let items: AnyObject = results["responseData"]["feed"]["entries"][index]["item"].rawValue
                        self.itemArray.addObject(items)
                    }
                    let barHeight: CGFloat = UIApplication.sharedApplication().statusBarFrame.size.height
                    let displayWidth: CGFloat = self.view.frame.width
                    let displayHeight: CGFloat = self.view.frame.height
                }
        }
        let myTableView: UITableView = UITableView(frame: CGRect(x: 0, y: 140 + barHeight, width: displayWidth, height: displayHeight - (140 + barHeight)))
        myTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
        myTableView.dataSource = self
        myTableView.delegate = self
        self.view.addSubview(myTableView)
   }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    // セクションごとの行数を返す
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.itemArray[section].count
    }
    // 各行に表示するセルを返す
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! UITableViewCell
        // セルに表示するテキストを設定
        cell.textLabel?.text = "セル" + (indexPath.row).description
        cell.detailTextLabel?.text = "サブタイトル"
        return cell
    }
    // セクション数
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return self.sectionArray.count
    }
    // セクションタイトル
    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sectionArray[section] as? String
    }
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        println("セクション\(indexPath.section)のセル\(indexPath.row)が選択された")
    }
}

ざっとコードはこんな感じ。

// セクション数
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return self.sectionArray.count
    }

JSONをパースしてからセクション数を決定するのですが、上記のコードでは必ずセクション数は0になります。
セクションのタイトルも無ければ行数も0。
何でかなー?とハマること数時間。。

何故かというと
パースしてる最中にテーブルを作成してしまっている
から。

self.view.addSubview(myTableView)

これを書いている位置が悪かったわけで、

Alamofire.request(.GET, jsonURLString, parameters: nil, encoding: .JSON)
            .responseJSON { (request, response, responseData, error) -> Void in

                (中略)
                    self.view.addSubview(myTableView)
                }

        }

JSONデータを受け取って処理してからaddSubViewしないとダメ。
.responseJSON {} の中ですね。

import UIKit
import SwiftyJSON
import Alamofire
class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var jsonURLString = "◯◯◯◯◯◯.json"
    // セクションのタイトル
    var sectionArray: NSMutableArray = []
    // 各要素
    var itemArray: NSMutableArray = []
    var sectionKosu: Int = Int()
    override func viewDidLoad() {
        super.viewDidLoad()
        // JSONのパース
        Alamofire.request(.GET, jsonURLString, parameters: nil, encoding: .JSON)
            .responseJSON { (request, response, responseData, error) -> Void in
                if let data: AnyObject = responseData {
                    let results = JSON(data)
                    let count: Int = results["responseData"]["feed"]["entries"].count
                    for index in 0..<count {
                        // タイトルの抜き出し
                        let title = results["responseData"]["feed"]["entries"][index]["ttl"].string!
                        self.sectionArray.addObject(title)
                        // セルの項目
                        let items: AnyObject = results["responseData"]["feed"]["entries"][index]["item"].rawValue
                        self.itemArray.addObject(items)
                    }
                 self.sectionKosu = self.sectionArray.count
                    let barHeight: CGFloat = UIApplication.sharedApplication().statusBarFrame.size.height
                    let displayWidth: CGFloat = self.view.frame.width
                    let displayHeight: CGFloat = self.view.frame.height
                    let myTableView: UITableView = UITableView(frame: CGRect(x: 0, y: 140 + barHeight, width: displayWidth, height: displayHeight - (140 + barHeight)))
                    myTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
                    myTableView.dataSource = self
                    myTableView.delegate = self
                    self.view.addSubview(myTableView)
                }
        }
   }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    // セクションごとの行数を返す
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.itemArray[section].count
    }
    // 各行に表示するセルを返す
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! UITableViewCell
        // セルに表示するテキストを設定
        cell.textLabel?.text = "セル" + (indexPath.row).description
        cell.detailTextLabel?.text = "サブタイトル"
        return cell
    }
    // セクション数
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return self.sectionArray.count
    }
    // セクションタイトル
    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sectionArray[section] as? String
    }
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        println("セクション\(indexPath.section)のセル\(indexPath.row)が選択された")
    }
}

上から順番に処理してくれると思い込んでいたので、「あれ?」っとなったのですが、考えてみれば当たり前のことでした。

 

pathForResourceでnilが返ってくるとき

プロジェクト内にファイル(例.mp4など)があるのにpathForResourceでnilが返ってくるときは

var myMoviePath = NSURL.fileURLWithPath(NSBundle.mainBundle().pathForResource("sample", ofType: "mov")!)

 

最初にプロジェクトに追加する際に「Add to targets:」の欄でプロジェクト名のところにチェックを入れたらnilになりません。

 

ハマったのでメモ。