たのしいSwiftプログラミング発売、さっそく正誤表や電子版のことなど

Share on Facebook
このエントリーをはてなブックマークに追加

久しぶりに新しい本を書きました。『たのしいSwiftプログラミング』です。昨日、10/26に発売になりました。

『たのしいCocoaプログラミング』(略称たのココ)に続く、たのしいシリーズです。新言語Swiftを使ったプログラミング入門書になっています。ターゲットとなる読者は、いままでまったくプログラミングの経験がない人。プログラムって何? というゼロの状態から、最初のアプリを組み上げるまでを説明します。

たのしいシリーズの特徴は、独特な語りかけるような文体で書かれていること。技術書らしからぬ読み口で、挫折せずに、最後まで一気に読ませます。

で、出したのですが、本に載っているサンプルが動かない、という状況が発生しています。これがですね、本の内容はiOS 8の正式版が出た時点ですべて検証したんですよ。校正して校了したのが10/8くらい。ふー、やれやれ、終わったー、と思っていたら、10/20にiOS 8.1が登場しました。まぁ、0.1のアップデートだからマイナーなバグ修正だよね、と思ってたら、何を考えたのかSwiftのAPIを変えてきやがりました。んな、アホな!

8.0から8.1のアップデートで、いままでコンパイルが通っていたSwiftのコードが通らなくなりました。APIの変更といっても微細なことで、オプショナル型が一部変わったんですね。あの、「!」とか「?」ってやつね。小さな変更でも、一箇所でもコンパイル通らなくなれば惨事になっちゃうよな。ベータのときもしょっちゅうオプショナル型変えていたから、嫌な予感はあったんだけども。

ということで、10/27に発売となったこの本は、登場した時点でコンパイルに失敗するコードが掲載されることになってしまいました。新しい言語なので仕様が固まっていないのはよくあることなんですけど、8.0から8.1で変更かけてくるのは納得いかないなあ。APIリファレンスの変更も追いついていないし。正直、憤りのあまり、銀座のApple StoreにいってiPhone 6 Plusを全部曲げてこようかと思いました。

サンプルや正誤表の方は、いま出版社さんとやり取りして準備してもらっています。少しお待ちください。明日中くらいにはなんとか。(追記:正誤表準備できました。http://www.bnn.co.jp/errata/7173/

このままってのもよろしくないので、電子版を準備しています。まずは、融通が利くアプリ型で。電子版は、iOS 8.1への対応、Yosemiteへの対応、いくつかの記述の追加などを加えた、rev.1.1的なものになります。

そうすると、紙の本を買っていただいた方に不利益が生じるので、特別価格か無料で提供できるよう、調整しています。問題になるのは、紙の本を買ったということを、どうやって判断するかですね。特に仕込みをしてなかったからなぁ。本の写真を撮ってTwitterにアップしてもらおうかな。

ちょっとしばらくバタつきそうですが、最新環境のキャッチアップして、継続的に更新できる環境を整えたいので、少しお待ちください。

  1. iOS開発に散々挫折してきたんですが今回は乗り越えることができそうです。
    すごく良い本だと思いました。さっそくですが続きを書いてください!

    • Aga
    • 2014年 10月27日

    木下様

    たのしいSwiftプログラミングを購入して、本当にSwiftを
    楽しく学ばさせていただいております。
    ですが、Tableを使おうで下記コードでエラーがでて困っております。
    お忙しいとは思いますが、教えていただけないでしょうか?
    よろしくお願いいたします。
    【コード】
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: “cell”)
    ではなく
    self.tableView.registerClass(UITableViewCell.self(NSObject), forCellReuseIdentifier: “cell”)

    (NSObject)がXcode6.1+iOS8.1では出てしまいます。

    Aga

      • mkino
      • 2014年 10月28日

      Xcodeの補間でself(NSObject)と出ますが、無視して、selfとだけ入力してください。

      クラス名に.selfを付けることで、そのクラスを取得することができます。

    • イニチェ
    • 2014年 10月27日

    以前、あるマンガで印刷ミスがあって出版社が交換をしていたことが
    あったんですが、そのときは交換申し込み兼購入証明の方法として
    「本の裏表紙のバーコード部分を切り取ってハガキに貼って出版社に送る」
    というものでした。
    後日、修正済みの本と50円切手が送られてきました。
    何かの参考になれば。

    • Aga
    • 2014年 10月28日

    Mkino様

    教えていただきありがとうござます。
    無視して実装したところ、無事
    テーブルを表示できました。

    • Ku
    • 2014年 10月28日

    電子版が出る予定とのことで大変楽しみにしています。よろしければ、おおよそいつ頃になるか教えて下さい。紙の本を買うかどうか悩んでいます。

      • mkino
      • 2014年 10月28日

      目標としては、来週頭申請なので、11月上旬には出したいと思っています。

        • Ku
        • 2014年 10月29日

        ありがとうございます、それなら電子版を待ちます。

    • ショッカー
    • 2014年 10月28日

    NSURLRequestとかdataTaskWithURL関連が軒並みエラーとなります(変数!にすると回避できます)。また、エミュレーターで、NSURLErrorDomain(RSS読み込み時)も発生します。検索するとXcodeのバグらしいですが、英語情報なので??です。回避方法があれば情報提供いただけると助かります。
    239ページのソースタイトルが違うようです(○ViewController.swift)。
    自前の開発環境がアレなので、NSURLErrorDomainが発生するのは、私だけかも・・・。その場合、ご容赦ください。

      • mkino
      • 2014年 10月28日

      NSURLやらUIImage回りでエラーが出るのは、iOS 8.1でオプショナルが大きく変わったせいです。正誤表で対応しますので、そちらを確認してください。
      NSURLErrorDomain関連のエラーも、Xcode 6.0では発生しなかったのが、Xcode 6.1から発生するようになりました。バグなのか仕様なのかは分かりません。とりあえず発生するのはPlaygroundだけみたいなので、とりあえず無視するのが良いかと思います。
      239ページのソースタイトルは、ご指摘の通りです。これは申し訳ないです。

        • ショッカー
        • 2014年 10月28日

        >とりあえず発生するのはPlaygroundだけみたいなので
        私の環境では、エミュレーターで発生(コンパイルしてrefresh実行時)します。Playgroundは、全てを試した訳ではありませんが、本のソースで問題なくできますよ(APIの差異はありますが)。・・・だとすると、私の環境下だけの問題なのでしょうね。ご容赦ください。

        Swift初心者なので、大変わかりやすい内容と感じました。正誤表又は、電子版お待ちしております。あと誤植ではないのですが、247ページのボタン配置ですが、次のページの上部の図を確認するまでNavigationの方にボタン配置してしまいました。あの図とサンプルがないとわかりませんでした。次回以降で改善頂けると良いかと思います。

        私の報告は以上です。返信ありがとうございました。

    • hiro_hosono
    • 2014年 10月30日

    電子版も期待しています。Amazonで買った人は判るんじゃないでしょうか?

    ところで「たのしいSwiftプログラミング」は略して「たのスィ」ってことで、帯に( *´∀`*)ノがあるのですかね?

      • mkino
      • 2014年 10月30日

      略称は「たのスイ」または「たのスィ」で呼んでいます。
      帯の顔文字は、デザイナーさんが本文を読んで感銘を受けて、あのデザインになったそうです。

    • fuji
    • 2014年 11月11日

    電子版を期待して、書籍を購入せずに待ってるのですが、いつ頃になりますでしょうか?
    まだ、時間かかりそうでしたら書籍を購入しようかと思っています。

      • mkino
      • 2014年 11月11日

      もうちょっとで出来上がるんですけど、審査の時間もあるので、
      今すぐ欲しいのであれば紙の書籍を購入してください。
      紙の書籍を購入した方には、なんらかの手段で電子版も読めるようにする予定です。

        • fuji
        • 2014年 11月11日

        わかりました。
        さっそく、アマゾンでポチっとして書籍が届くのを待つとします。
        電子版の方も、期待してまっています。

    • koko
    • 2015年 1月13日

    初めまして。
    電子版を購入し読ませていただいてます。
    プログラミング初心者なので、書かれているサンプルを打ち込みながら勉強しています。
    唐突ですが、わからないところがありまして教えていただけると助かります。

    5-2-3 もうちょっと遊ぼうでテーブルに「iphoneの種類」と「発売された年」を表示する
    サンプルについてですが、

    //セルのクラスを設定する
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: “cell”)
    にある①「forCellReuseIdentifier: “cell”」

    //セルをここで作成する
    var cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: “detailCell”)
    にある②「reuseIdentifier: “detailCell”」
    の関係がよくわかりません。
    ①が「cell」なら②も「cell」の方がいいのではいいのでは??と思い
    同じにしてみて実行しても見た目同じように表示されました。
    でも実行後時間が経つとエラーになるのではとも考えましたがよく分かりません。
    また、①は一つ前のサンプルの流れであるだけで機能していないのではと思ってみたり。実際に
    viewDidLpad()オーバライド部分を削除して実行してもテーブルは見た目同じように表示
    されました。viewDidLpad()のオーバライド部分はここでは不要ではと考えてみたり???
    セルの再利用の識別子だとするとセルの作り方によって変わるのでしょうか?
    教えていただけると助かります。よろしくお願いします。

    それから電子版に対する要望なんですが、画面のスワイプでページが移動するのは
    すごく使いやすいのですがタップでのページ移動は設定でオフに出来ると助かります。
    不意に画面に触れてしまいページが移動してしまうことが多々ありましたので
    出来れば対応していただけると助かります。

    お願いばかりで申し訳ありませんがよろしくお願いします。

      • mkino
      • 2015年 1月17日

      テーブルのセルの作り方は、歴史的な経緯でいくつかあって、
      1. 明示的にインスタンスを作って登録する
      2. クラスを登録してdequeueする
      3. プロトタイプセルをdequeueする
      って感じです。
      1.が古くて、最近は2.か3.を使うのがオススメです。

      なので本では、まず2.を使っています。

      でも、テーブルセルには、detailLabelというサブテキストを表示するものがあります。
      これが、2.のやり方だと利用できないんですね。
      なので、detailLabelを使うために1.のやり方も説明した、という感じです。
      1.のやり方の場合は、クラスの登録が必要ないので、
      registerClassを呼ばなくとも動きます。

      こちらも参考にしてみてください。

      http://hmdt.jp/blog/?p=1272

      あと、電子版の操作に対する要望は承りました。
      実際にどのように対応するかは、ユーザインタフェース全体を考えての判断になります。

        • koko
        • 2015年 1月17日

        ご回答ありがとうございます!!
        大変勉強になります。

        ご回答にある
        1.のやり方の場合は、クラスの登録が必要ないので、
        registerClassを呼ばなくとも動きます。

        ということですが

        1.のやり方でregisterClassを呼ぶと問題はないのでしょうか?
        なんどもすみません、教えてください。
        よろしくお願いします。

          • mkino
          • 2015年 1月20日

          >1.のやり方でregisterClassを呼ぶと問題はないのでしょうか?

          問題ないです。
          1.と2.は、共存できます。

          dequeueResulableCellWithIdentifierを呼び出すときの識別子で、使い分けます。
          だから、本文のコードでは、別の識別子を割り当てています。

            • koko
            • 2015年 1月20日

            ご回答ありがとうございます。
            ようやくわかったような気がします。

            //セルをここで作成する
            var cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: “detailCell”)
            の「reuseIdentifier: “detailCell”」も再利用のための識別子を設定しているのですね。

            セルを作成しているところなので
            「reuseIdentifier: “detailCell”」をキーにして再利用可能なセルがあるか確認してから作成するのかと思っていました。

            そうすると・・・
            再利用のための識別子が2つ・・・。
            使い分けるということですね。

            どんな場合に使い分けるのだろう?
            1つ分かるとまた1つわからないことが出てきますね。
            でも楽しい・・・たのスィ ですね(^^)

    • koko
    • 2015年 2月6日

    こんばんは。

     前回ご質問をさせていただいてからも分からないことをネットで検索したりしながら
    読ませていただいております。(^^)
    またまたどうしても分からないことが出てきました。
    クロージャの引数についてなのですが、3-9-3クロージャの文法ではarg0,arg1,arg2それぞれ
    クロージャを呼び出す前に定義と値の設定があり、それらをクロージャに引き渡して
    いますが
    その後もよく出てくる
    NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { data, response, error in
    ・・・・・
    })
    のdata, response, errorにはクロージャを呼び出す前の定義と値の設定が無いように思います。
    クロージャも関数と同じように引数でデータの引き渡しをするのであればクロージャの外での定義と値の設定が必要なのではないのでしょうか?(データの引き渡しをしているのではないのでしょうか?)
    教えていただけないでしょうか。
    よろしくお願いします。

      • mkino
      • 2015年 2月9日

      えっと、data, response, errorに関して言えば、
      これらはNSURLSession.swiftの中で定義されています。
      Cocoa touch側が定義しているクロージャの型をそのまま使っているので、
      こちらで定義する必要はありません。

      3-9-3の説明は、あえて、こっちでクロージャの型を定義しています。
      どうやって定義するのか説明するためです。

      分かりにくかったかなぁ。

        • koko
        • 2015年 2月10日

        こんばんは!

        >これらはNSURLSession.swiftの中で定義されています。
        と次のコメントに対しての
        >Cocoa的に言うと、クロージャは主にコールバックの仕組みの一環として使われます。
        で、なんとなくわかったような気がします。

        3-9-3の
        //handlerを呼び出す。ここでは、これがクロージャとなっている
        ①handler(arg0,arg1,arg2)
        のarg0,arg1,arg2という引数名と

        //引数として、クロージャを渡す
        ②dataDownload({(arg0,arg1,arg2)->Int in
        のarg0,arg1,arg2引数名は同じでなくてもいいということですよね。

        ①と②を結びつけているのは、本文でも説明していただいているように
        //dataDownload関数の定義
        ③func dataDownload(handler:(String,String,String)->Int){
        の引数の型と数、戻り値 (String,String,String)->Int の
        部分であり、

        func dataDownloadの中でのクロージャの呼び出し部分①と
        関数の定義部分・・・③を結びつけているのは
        ①の関数名と③の「handler:」というラベル?ですよね。

        質問に答えていただきありがとうございました。
        (間違ってましたらご指摘いただけると助かります(^^;))

        それから
        NSURLSession.sharedSession().dataTaskWithURLに関して
        6-3-2 データをダウンロードしてみる
        NSURLSessionクラスの
        func dataTaskWithURL(url:NSURL,completionHandler:((NSData!,NSURLResponse!,NSError!)->Void)?)->NSURLSessionDataTask
        クロージャ部分の引数の型がNSData!,NSURLResponse!,NSError!とすべてに
        「!」が付いているのですがこれはどういう意味なのでしょうか?
        またまた質問で申し訳ありません。
        教えてください。よろしくお願いします。

          • koko
          • 2015年 2月14日

          クロージャでは引数名がなく型名に「!」がついていたので何か特別な意味があるのかと思っていましたが、Playgroundで変数定義の方法をいろいろ試してみて通常の宣言ときっと同じだということが分かりました。

          電子版を開いてみたら内容が1.3にアップデートするか確認するメッセージがでました!
          アップデートしたのですがどの部分が変わったのかよく分かりません。(ーー;)変更箇所がある場合、その部分がどこかが分かると助かります。例えば3-9-1を全面改訂とか。全部読み直さないと変更箇所が分からないのは厳しいです。

            • mkino
            • 2015年 2月15日

            型名の「!」は、オプショナルで、それはそれで意味があります。
            ただ、クロージャそのものとはそんなに関係ないですね。
            クロージャは引数をとって、その方は「!」が付いたり付かなかったりします。

            >電子版を開いてみたら内容が1.3にアップデートするか確認するメッセージがでました!
            >アップデートしたのですがどの部分が変わったのかよく分かりません。

            更新内容は、「はじめに」の最後の方に書いてあるので、
            そちらを参照してください。
            1.3は、コメント機能への対応が主です。

    • 通りすがり
    • 2015年 2月8日

    アプリ版の方、非常に分かりやすく勉強させていただいております。

    3-9-1 クロージャの説明部分がちんぷんかんぷんです。
    その理由は、サンプルソースがなんの目的で書かれたソースで、こう書く事でなにが達成できるからすごく便利、という部分が分からない為だと思います。

    お忙しいところ恐縮ですが、さらに猿でも分かる感じに噛み砕いていただけないでしょうか?

      • mkino
      • 2015年 2月9日

      別のコメントにもありましたけど、クロージャの説明は分かりにくかったですね。

      Cocoa的に言うと、クロージャは主にコールバックの仕組みの一環として使われます。
      クロージャ以前は、デリゲートという方法を使っていて、
      これだと一連の処理を書いているはずなのに、ソースコードがバラバラになってしまいました。
      それが、クロージャを使うと、おぉ、一箇所にまとまってうれしいぜ、
      ってのが便利なところです。

      クロージャ以前の、デリゲートを使ってた時はどうだったのか、
      ていうことろから書くと分かりやすいかな。
      ちょっと、書き直してみます。

        • 通りすがり
        • 2015年 2月16日

        お手数をおかけして恐縮です。

        楽しみにしています!

    • koko
    • 2015年 2月16日

    返信ができなかったのでこちらに書かせていただきました。
    ご回答ありがとうございます。

    やはりオプショナルですよね。(^^)
    オプショナルは変数に「?」をつけて「!」でアンラップと思っていましたので
    変数部分でしかも型に「!」がついていましたのでびっくりしました。
    「!」をつけるオプショナルがあることを知り理解することができました。
    でも、これから自分でクラスをつくるようになり、変数を宣言し、メソッドの
    引数を決めたりする際にオプショナルにするのかどうか、オプショナルでも「?」に
    するのか「!」にするのかswiftならではの(swiftしか知りませんが・・・)難しさ
    がありそうですね。
    なにかルールとかガイドラインなんかがあるんでしょうかね〜。(^^)
    ①絶対に値があるものはオプショナルなし
    ②あるかどうか分からないものは「?」
    ③絶対に値はあるが初期化の時などに一時的にnilになる場合は「!」
    とかですかね?
    func dataTaskWithURLのクロージャ引数であるNSData!,NSURLResponse!,NSError!はインスタンスが出来てからダウンロードが始まるまではnilの状態があってもクロージャ呼び出し時はダウンロードが完了後だから確実にデータがあるので「!」を使っているということなんでしょうか。でもダウンロードに失敗することもあると考えるとNSData!とNSError!ともにデータが入っていることって無いような・・・?きっとNSError!って名前のとおりエラーの場合だけ値が入るんですよね?
    難しいですね。(ーー;)
    mkino様はオプショナルの使い分けどのようにお考えなのでしょうか。

      • mkino
      • 2015年 2月19日

      SwiftとObjective-Cを比べた時、
      使い勝手の上での一番の差異は、やっぱりオプショナルだよな、と感じています。

      オプショナルの使い方は、一般的なプログラムでどうすべきかという話と、
      Cocoaでどう使われているか、ということを分けて考えないとこんがらがりそうです。

      特にCocoaの使い方を見ると、私の感想では、Assert的な使い方をしているんでは、
      と感じています。
      というのは、Cocoa APIはやたらと「!」が多いんですよね。
      「!」にnilが来ると例外が発生するので、なんとなく「?」つけてりゃいいや、
      って思っちゃうんですが、
      どうもCocoaは意図的にそれを狙いに来ているんではないかと。

      つまり、プログラム的にここにnilが来たらどうにも動かないよ、
      というところで「!」を使って、積極的に落としにかかっている、と。
      ここをなぁなぁに済ませると、後で原因不明のバグになっちゃうよ、
      っていう思想なのかなぁ、と感じています。

      リリース前に絶対つぶさないといけない問題を洗い出そうということで、
      わかっている人にはありがたいですけど、
      そうじゃない人にはやたら落ちるという印象になるかも。

    • 破壊王
    • 2015年 4月22日

    7-4-4 デーブルのデータメソッドを実装しよう!
    全て打ち込んで実行すると、

    19行目 
    var task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { data, response, error in

    のところに黄緑色のラインが出てきてうまく実行できません。
    初心者で何がエラーなのか自分でもわからないので教えていただきたいです。

    下の方に
    A sender
    A self
    L url
    L task

    と出てきています。

    • tana00
    • 2016年 5月19日

    ご著書の「たのしいSwiftプログラミング」のに掲載のコードへの質問をさせて下さい。
    SwiftNews Part9プロジェクトのViewController.swiftの中にrefreshボタンを押した時の処理が記述されています。JSON形式でWebサイトから受け取ったサイトサマリーを日付順にソートする部分の処理が冗長に思えます。

    コードを抜粋します。
    // エントリーをソートする
    self.entries.sortUsingComparator({ object1, object2 in
    // 日付を取得する
    let date1 = object1[“date”] as! NSDate
    let date2 = object2[“date”] as! NSDate

    // 日付を比較する

    let order = date1.compare(date2)

    // 比較結果をひっくり返す
    if order == NSComparisonResult.OrderedAscending {
      return NSComparisonResult.OrderedDescending
    }
    else if order == NSComparisonResult.OrderedDescending {
    return NSComparisonResult.OrderedAscending
    }
    return order
            })
    変数entriesはNSMutableArray型でそのメソッドsortUsingComparatorは、引数にNSComparatorブロックを要求します。NSComparatorブロックは、
    typealias NSComparator = (AnyObject, AnyObject) -> NSComparisonResult
    と定義されており、要するに NSComparisonResult列挙体を返すブロックです。

    ご著書に掲載のコードではNSDate型のcompareメソッドがNSComparisonResult列挙体を返す事を利用して、ブロックの戻り値を作っています。しかし、かなりややこしい処理をしているように見えます。
    単に次の様に記述しては問題があるのでしょうか?
    // エントリーをソートする
    self.entries.sortUsingComparator({ object1, object2 in
    // 日付を取得する
    let date1 = object1[“date”] as! NSDate
    let date2 = object2[“date”] as! NSDate

    return date2.compare(date1)
            })

    data1のcompareメソッドを呼んでいたのを、data2のcompareメソッドを呼ぶようにしました。

      • mkino
      • 2016年 5月19日

      その通りですね。そちらの方が簡潔でいいコードだと思います。

      ただ、解説書としては、compareん返り値としてNSComparisonResult.OrderedAscendingや、NSComparisonResult.OrderedDescendingが来ることを例示したコードがあるといいだろう、とも考えます。

      なので、まず現状のコードを示して、その後に「あぁー、これだとなんかめんどくせーな、もっとこう書いたらいいかも?」という趣旨で、date2.compare(date1)を使ったコードがあるといいのかもしれません。そうしてみます。

        • tana00
        • 2016年 5月20日

        早速のご返答ありがとうございました。
        ご著書掲載のコードの//比較結果をひっくり返す、コメントがある部分には、どんな意味があるのか疑問に思って質問させて頂きました。ご回答でスッキリしました。ありがとうございました。

  1. トラックバックはまだありません。