「SwiftUI」AppDelegate.swiftとSceneDelegate.swiftファイルがない場合

参考書を使ってSwiftUIの学習をしていた時に、タイトルにある二つのファイルが見つからず混乱したので、原因をメモしておきます。

 

どうやらXcode12からプロジェクトを作成する時に「Life Cycle」という項目が追加され、SwiftUI AppとUIKit App Delegateの二つから選べるのですが「UIKit App Delegate」を選ばないと「AppDelegate.swift」と「SceneDelegae.swift」は生成されないそうです。f:id:KEICON:20210428202436p:plain

上記の画像のように、プロジェクト作成時にLife Cycleを「UIKit App Delegate」にしてください。

 

Life Cycleの違いは下記の記事が参考になりました。

 

 

 

www.rk-k.com

SwiftUI徹底入門「@ObservedObject」の仕組みが変わった?

SwiftUI徹底入門の10章「@ObservedObject」を学習していた時に、本に書いてある通りにコードを書いても上手くいかなかったので、修正した流れを残しておきたいと思います。

本書では以下のコードが記述されていました。

class MyData: ObservableObject {
    @Published var score = 0
}

struct ContentView: View {
    @ObservedObject var data: MyData
    var body: some View {
        VStack {
            Text("\(data.score)")
            Button(action: {
                self.data.score += 1
            }) {
                Text("カウントアップ")
            }
        }
    }
}

そして この画像のように文字を押すとカウントされるという仕組みですが、

f:id:KEICON:20210427120222p:plain

上記のコードのままだと「Missing argument for parameter 'data' in call」とエラーが出てしまいます。 f:id:KEICON:20210427112819p:plain

原因を調べてみると、おそらくこの本が発売された頃はパラメータを渡さなくても使えたようですが、現在は仕様が変わったっぽい? developer.apple.com

なので今回はクラスにイニシャライザを設定することで対処しました。(以下ContentView.swiftの全体コード)

import SwiftUI
import AVKit

class MyData: ObservableObject {
    @Published var score: Int
    init(score: Int) {
        self.score = score
    }
}

struct ContentView: View {
    @ObservedObject var data = MyData(score: 0)
    var body: some View {
        VStack {
            Text("\(data.score)")
            Button(action: {
                self.data.score += 1
            }) {
                Text("カウントアップ")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

「シミュレーターが起動しない」Unable to boot device due to insufficient system resources

タイトル通りのエラーが発生し、調べてみると実行可能なプロセスを増やす必要があるという記事が多かった。しかし、「システムの速度が低下し、OSが不安定になる可能性がある」との記述から別の方法を探ることにした。

 

おそらく、過去に作ったプロジェクトのシミュレーターの情報が溜まって新しく起動できないのだろうと思い、そのフォルダを削除したら解決することができた。

 

以下手順

 

1 「option」を押しながら、移動を選択すると「ライブラリ」と出てくるので、それをクリックする。

(画像はライブラリが表示されてないです、すみません)

f:id:KEICON:20210420124019p:plain

 

 

2 ライブラリに移動した後「Developer」フォルダを開き、その中にある「xcode」フォルダを開いてください

 

3 xcodeフォルダを開くと「DerivedData」フォルダがあるので選択して削除してください。

 

※ DerivedDataフォルダ以下のような情報が保存されています。

  • ビルド時に生成されるバイナリファイルやデータファイル
  • インデックス情報
  • ビルドやテストなどのログ
  • ソースコードのシンボル情報

 

削除後はシミュレーターを動かすことができました!

プライバシーポリシー(ネコカウンター)

はじめに

このページでは、あなたの情報を猫カウンター(以下「本アプリ」と称します。)がどのように取り扱うかを説明します。本アプリのご使用によって、本規約に同意していただいたものとしてみなします。

 

あなたの情報

本アプリは、個人を特定するために利用できる一切の個人情報を、収集又は補完しません。

一方、本アプリは、以下の情報をあなたのデバイス上で使用及び保管します。

 ● 現在のカウント数

 ● 現在の背景画像

 ● タップ時の音声をONにするかOFFにするかの選択

 ● いいねのアニメーションをONにするかOFFにするかの選択

 ● タップ時に背景画像を固定するかの選択

 ● ユーザー名

以上の情報は暗号化されません。

本アプリは、以上の情報をデバイスから転送せず、いかなるウェブサイト又はサービスとも共有しません。

 

免責事項

本アプリあユーザーの特定の目的に適合すること、期待する機能・正確性・有用性を有すること、及び不具合が生じないことについて、何ら保証するものではありません。

当方の都合によりアプリの使用を変更できます。私たちは、本アプリの提供の終了、変更、又は利用不能、本アプリの利用によるデータの消失又は機械の故障もしくは損傷、その他本アプリに関してユーザーが被った損害につき、賠償する責任を一切負わないものとします。

 

お問い合わせ

お問い合わせフォーム

パーフェクトPHP 6章のコードが古いのでPHP7に対応できるよう書き換えてみた

こんにちは!  この記事を見ている方は、恐らくパーフェクトPHP第6章のひとこと掲示板が上手く表示されない、データが保存されないといった状況に陥っている方が多いと思います。 僕も、第6章でなかなかデータを保存することができず時間がかかったので、PHP7でも実行できるように書き換えたコードをメモとして残しておきます。

mysql_*関数は「非推奨」又は「使えない」

パーフェクトPHPに記載されている、mysql_connect等のmysql_とつく関数はPHP5.5以降は非推奨、PHP7では削除されています。
そのため、PHP7の環境の場合は書籍に書いてあるコードのままでは動作しません。(PHP5系なら一応動くと思います。)
非推奨になった理由としては、セキュリティの脆弱性であったり、mysqlの最新の機能に対応してない等が主な理由らしいです。
こちらのLIGさんの記事がまとめてあって読みやすかったです。

使っちゃいけない! PHPのmysql_* 系関数の取り扱いに関する海外の見解 | 東京のWeb制作会社LIG

mysqli関数を使って書き換えてみる

上記の理由から、PHP7に対応していて、書き方も書籍と似ているmysqli関数を使いたいと思います。
mysqli関数はオブジェクト型と手続き型の2種類の書き方があるのですが、サンプルコードに一番近い形にするため手続き型を使用しています。

以下全体のコード

<?php
    $link = mysqli_connect('localhost', 'root', '');    
    
    if(!$link) {
        die('データベースに接続できません:' . mysqli_error());
    }

    // データベースを選択する
    mysqli_select_db($link ,'oneline_bbs');
    $errors = array();

    // POSTなら保存処理実行
    if($_SERVER['REQUEST_METHOD']  ===  'POST') {
        $name = null;
        if(!isset($_POST['name']) || !strlen($_POST['name'])) {
            $errors['name'] = '名前を入力してください';
        } else if(strlen($_POST) > 40) {
            $errors['name'] = '名前は40文字以内で入力してください';
        } else {
            $name = $_POST['name'];
        }

        // ひとことが正しく入力されているかチェック
        if(!isset($_POST['comment']) || !strlen($_POST['comment'])) {
            $errors['comment']  = 'ひとことを入力してください';
        } else if(strlen($_POST['comment' ])  > 200) {
            $errors['comment']  = 'ひとことは200文字以内で入力してください';
        } else {
            $comment = $_POST['comment'];
        }

        // エラーがなければ保存
        if(count($errors)  === 0) {
            $sql = "insert into post (name, comment, created_at) values (
                '" . mysqli_real_escape_string($link,$name) . "','"
                . mysqli_real_escape_string($link,$comment) . "','"
                . date('Y-m-d H:i:s') . 
                "')";

            // 保存する
            mysqli_query($link, $sql);
            mysqli_close($link);
            header('Location: http://' .$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
        }        
    }
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ひとこと掲示板</title>
</head>
<body>
    <h1>ひとこと掲示板</h1>

    <form action="bbs.php" method="post">
        <?php if (count($errors) > 0): ?>
            <ul class="error_list">
                <?php foreach($errors as $error): ?>
                    <li>
                        <?php echo htmlspecialchars($error, ENT_QUOTES, 'UTF-8'); ?>
                    </li>
                <?php endforeach; ?>
            </ul>
        <? endif; ?>
        名前: <input type="text" name="name" size="60"><br>
        ひとこと: <input type="text" name="comment"><br>
        <input type="submit" name="submit" value="送信">
    </form>
    <?php  
        // 投稿された内容を取得するSQLを作成して結果を取得
        $sql = "select * from post order by created_at desc;";
        $result = mysqli_query($link, $sql);
    ?>
    <?php if($result !== false && mysqli_num_rows($result)): ?>
        <ul>
            <?php while($post = mysqli_fetch_assoc($result)): ?>
                <li>
                    <?php echo htmlspecialchars($post['name'], ENT_QUOTES, 'UTF-8'); ?>:
                    <?php echo htmlspecialchars($post['comment'], ENT_QUOTES, 'UTF-8'); ?>
                    - <?php echo htmlspecialchars($post['created_at'], ENT_QUOTES, 'UTF-8'); ?>
                </li>
            <?php endwhile; ?>
        </ul>
    <?php endif; ?>

    <?php 
        mysqli_free_result($result);
        mysqli_close($link);
    ?>
</body>
</html>

注意点

ほとんどmysqlがmysqliになっただけのような気がしますが、注意して欲しいのは引数の順番です。

mysqli_select_db($link, 'oneline_bbs');
mysqli_query($link, $sql);

この2箇所は書籍と引数の順番が逆になっています。mysqliでは第一引数に接続先のmysqlオブジェクトが必要です。

また、

$sql = "insert into post (name, comment, created_at) values (
                '" . mysqli_real_escape_string($link,$name) . "','"
                . mysqli_real_escape_string($link,$comment) . "','"
                . date('Y-m-d H:i:s') . 
                "')";

この文にある、mysqli_real_escape_string関数は手続き型の書き方では引数に文字列と接続先のmysqlオブジェクトが必要です

mac ターミナルの文字の色が急に消えてしまった場合の対処法

homebrewのインストール作業を中途半端なところで中止してしまったら、ターミナルの設定が反映されなくなり、プロンプト($マーク以前の文字のことです)が真っ白な状態になってしまいました。

 

解決方法をメモしておきます。

 

プロンプトの設定は環境変数である「PS1」を読み込んで表示されます。

 

このPS1はおそらく .bashrc 又は.bash_profileのどちらかに設定されていると思うのですが、何らかの影響でターミナル起動時にこれらのファイルを読み込めていないことが原因だと思われます。

 

なので、

source ~/.bashrc

又は

source ~/.bash_profile

を実行すれば色が戻ると思われます。


ターミナルを落とすと元に戻ってしまう場合

おそらくPS1を.bashrcに記入している場合だと思うのですが、ターミナル起動時に.bashrcが読み込まれていないので、 .bash_profileに下記を記述してください

if [ -f ~/.bashrc ] ; then
. ~/.bashrc
fi

その後sourceコマンドで.bash_profileを読み込めば、大丈夫です。

 

 

パーフェクトPHP 5.3.2 遅延的束縛がわからない仲間へ

パーフェクトphpを学習していて、遅延静的束縛で少し困惑したので、自分なりにわかりやすくまとめておきます。

多分、遅延静的束縛で混乱するところはselfとstaticの違いだと思います。 なんでselfからstaticに変えたら親クラスではなく子クラスのメソッドを呼び出せるのか。

まず、前提として理解しておきたいのは
・selfは定義時のクラスを示す
・staticは実行時のクラスを示す

この2点です。

では実際にコードで確認してみます。

<?php
    class Father {
        public function family() {
            self::member();
        }

        public static function member() {
            echo '私は父です', PHP_EOL;
        }
    }

    class Son extends Father {
        public static function member()
        {
            echo '私は息子です', PHP_EOL;
        }
    }

    $son = new Son();
    $son->family();

このコードは、Fatherクラスを継承したSonクラスのインスタンスを作り、自己紹介をしてもらうプログラムです。 Sonクラスのインスタンスを生成したので期待する結果は「私は息子です」なのですが、実行すると「私は父です」になってしまいます。

原因は「selfは実行時のクラスを示す」からです。 つまり、self::member();は実際には

Father::member();

となっていて親であるFatherクラスのmemberメソッドを参照してしまっているわけです。

これを解決するために self::memberの部分を

static::member();

に変更すれば、staticは実行時のクラスを示すので

Son::member();

という動きになり、期待していた出力結果の「私は息子です」になります。

これでインスタンスごとに特有の処理ができるので拡張性が高くなりますね! 以上が遅延静的束縛です。



ここまで読んでいただきありがとうございます。間違い等がありましたらご指摘いただければ幸いです。