【iOS】MarkdownをHTMLにレンダリングするライブラリを使って、Qiitaの記事をMarkdownで表示してみた


## はじめに

iOS Second Stage Advent Calendar20日目の記事です。

個人的には7記事目になります。

## 本題

**Markdown**を描画するライブラリを見つけたので、それを使用してQiitaの記事を用事するサンプルをつくってみました。

ライブラリは[mdiep/MMMarkdown](https://github.com/mdiep/MMMarkdown)です。

サンプルプロジェクトは以下においておいきました。

[AdventCalendar2015/SampleMMMarkdown at master · ryokosuge/AdventCalendar2015](https://github.com/ryokosuge/AdventCalendar2015/tree/master/SampleMMMarkdown)

## スクリーンショット

- 一覧
	
	![スクリーンショット 2015-12-20 0.27.39.png](https://qiita-image-store.s3.amazonaws.com/0/47302/4c6d6f78-0d1f-a203-d9f3-25a0a086f5b3.png "スクリーンショット 2015-12-20 0.27.39.png")

- 詳細

	![スクリーンショット 2015-12-20 0.28.07.png](https://qiita-image-store.s3.amazonaws.com/0/47302/79446bc0-e342-8c17-42ee-c3df78c97415.png "スクリーンショット 2015-12-20 0.28.07.png")

こんな感じで表示できました。

## 導入

`MMMarkdown`は`Carthage`か自分でコピーするとのことなので`Carthage`を使用して導入しました。

`Carthage`での導入方法などは世にたくさん出ているので、そちらを参考にしてください。

ちなみに今回使ったライブラリは以下になります。

```ruby:Cartfile
## Himotoki
## source: https://github.com/ikesyo/Himotoki
github "ikesyo/Himotoki" ~> 1.3

## Alamofire
## source: https://github.com/Alamofire/Alamofire
github "Alamofire/Alamofire" ~> 3.0

## BrightFutures
## source https://github.com/Thomvis/BrightFutures
github "Thomvis/BrightFutures" ~> 3.2

## MMMarkdown
## source https://github.com/mdiep/MMMarkdown
github "mdiep/MMMarkdown"
```

最近`Himotoki`を使うのが自分の中でのブームになっています。

## ソースコード

`Qiita`のAPIから記事のMarkdownの値が取得できるので、それを使ってやりました。

### Himotokiを使ってレスポンスを構造体に変換

以下は`Qiita`APIから取得できるレスポンスを保持する構造体です。

```swift:ItemResponse.swift

import Foundation
import Himotoki

struct TagResponse: Decodable {
    let name: String
    let versions: [String]
    
    static func decode(e: Extractor) throws -> TagResponse.DecodedType {
        return try TagResponse(name: e <| "name", versions: e <|| "versions" )
    }
    
}

struct UserResponse: Decodable {
    
    let description: String?
    let facebookID: String?
    let followeesCount: Int
    let followersCount: Int
    let githubLoginName: String?
    let id: String
    let itemsCount: Int
    let linkedinID: String?
    let location: String?
    let name: String
    let organization: String?
    let permanentID: Int
    let profileImageURL: String
    let twitterScreenName: String?
    let websiteURL: String?
    
    static func decode(e: Extractor) throws -> UserResponse.DecodedType {
        return try UserResponse(description: e <|? "description", facebookID: e <|? "facebook_id", followeesCount: e <| "followees_count", followersCount: e <| "followers_count", githubLoginName: e <|? "github_login_name", id: e <| "id", itemsCount: e <| "items_count", linkedinID: e <|? "linkedin_id", location: e <|? "location", name: e <| "name", organization: e <|? "organization", permanentID: e <| "permanent_id", profileImageURL: e <| "profile_image_url", twitterScreenName: e <|? "twitter_screen_name", websiteURL: e <|? "website_url")
    }
    
}

struct ItemResponse: Decodable {
    
    let renderedBody: String
    let body: String
    let coediting: Bool
    let createdAt: String
    let id: String
    let privateItem: Bool
    let tags: [TagResponse]
    let title: String
    let updatedAt: String
    let URL: String
    let user: UserResponse
    
    static func decode(e: Extractor) throws -> ItemResponse.DecodedType {
        return try ItemResponse(renderedBody: e <| "rendered_body", body: e <| "body", coediting: e <| "coediting", createdAt: e <| "created_at", id: e <| "id", privateItem: e <| "private", tags: e <|| "tags", title: e <| "title", updatedAt: e <| "updated_at", URL: e <| "url", user: e <| "user")
    }
    
}
```

`ItemResponse`の中の`body`の値が投稿のMarkdownテキストになっています。

詳しくは[Qiita API v2 ドキュメント](https://qiita.com/api/v2/docs#投稿)を参照ください。

ではそれを描画するのに **MMMarkdown**を使用してみます。

### Markdownの描画

以下のページを参考にしてやってみました。

[initWithFunk: by Eric Allam](http://initwithfunk.com/blog/2013/09/29/easy-markdown-rendering-with-nsattributedstring-on-ios-7/)

描画には`UITextView`を使用しています。

それのソースコードは以下になります。

```swift:DetailViewController.swift
import UIKit
import MMMarkdown

class DetailViewController: UIViewController {
    
    static func instantiateViewControllerWithItem(item: ItemResponse) -> DetailViewController {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
        viewController.item = item
        return viewController
    }
    
    @IBOutlet weak var textView: UITextView!
    private var item: ItemResponse!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        setupView()
    }

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

}

/// MARK: - private methods.
extension DetailViewController {
    
    private func setupView() {
        if let htmlString = try? MMMarkdown.HTMLStringWithMarkdown(item.body) {
            let style = "<style>img { max-width: 300px; height: auto; }</style>\n"
            let body = style + htmlString
            print(body)
            if let data = body.dataUsingEncoding(NSUnicodeStringEncoding) {
                let attribute = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
                if let attributeText = try? NSAttributedString(data: data, options: attribute, documentAttributes: nil) {
                    textView.attributedText = attributeText
                }
            }
        }
        textView.editable = false
    }
    
}
```

`DetailViewController`の`setupView()`の中でMarkdownを表示するテキストに変換しています。

これだけで表示することができました。

### 余談

`let style = "<style>img { max-width: 300px; height: auto; }</style>\n"`を追加しているのは **画像がそのままのサイズで表示されているから**です。

比率を保ったまま、表示するので適当に設置してみました。

あと`UITextView`ですが、かなり色々できるクラスになっています。

以下のページがわかりやすく紹介してくれているので参考にするといいかと思います。

[iOS - [Objective-C] HTMLを使って文章をスタリングする - Qiita](http://qiita.com/edo_m18/items/e7983886fc39ed7e3ecb)

## 終わりに

Markdownを返してくるサービス（API）ってあまり見かけませんが、自社サービスとか社内サービスとかにはいいかもですね。

以上になります。

## 参考

- [mdiep/MMMarkdown](https://github.com/mdiep/MMMarkdown)
- [initWithFunk: by Eric Allam](http://initwithfunk.com/blog/2013/09/29/easy-markdown-rendering-with-nsattributedstring-on-ios-7/)
- [iOS - [Objective-C] HTMLを使って文章をスタリングする - Qiita](http://qiita.com/edo_m18/items/e7983886fc39ed7e3ecb)