[Swift4/iOS] TextField で開いたキーボードを閉じる

TextFieldをもつiOSアプリでユーザの特定のアクションでキーボードを閉じるためのコードです。

キーボードの『改行』キーを押された場合にキーボードを閉じる

  • 表示するViewControllerクラスにUITextFieldDelegateを継承させる
  • TextFieldのdelegateにselfを指定
  • textFieldShouldReturnを実装しtextField.resignFirstResponder()を呼ぶ

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!

    /* 略 */

    override func viewDidLoad() {
        super.viewDidLoad()
        textField.delegate = self
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool{
        textField.resignFirstResponder()
        return true
    }    
}

TextField以外をタップされたらキーボードを閉じる

  • touchesBeganを実装しself.view.endEditing()を呼ぶ

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    /* 略 */    
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }
}

[C++] std::stringにキャストされた場合に文字列を返すようにする

クラスのオブジェクトがstd::stringとしてキャストされた場合任意の文字列を返すようにする。
ロギングなどで複数の別々のクラスをstringとして扱って統計情報などを出力したりするのに使える。

#include <iostream>
#include <string>

class Coordinate {
private:
    int _x;
    int _y;
public:
    Coordinate(int x, int y): _y(y), _x(x) {}
    explicit operator std::string () const {
        return "x=" + std::to_string(_x) + ", y=" + std::to_string(_y);
    }
};

int main() {
    Coordinate coord(300, 400);
    std::cout << static_cast(coord) << std::endl;
}

[C++] オブジェクトのアドレスを表示

オブジェクトのアドレスを表示するコードです。
一言で言えば stati_cast で void のポインタにキャストして stream に渡してるということです。

#include <iostream>
#include <vector>

void showAddress() {
    
    std::vector<char> vec(100);
    
    //vectorオブジェクトのアドレスを表示
    std::cout << "vec   = "
         << static_cast<void *>(&vec)
    << std::endl;
    
    //vector内部で使われているバッファのアドレスを表示
    std::cout << "data  = " <<
         static_cast<void *>(vec.data())
    << std::endl;

    // new して確保したchar配列のアドレスを表示
    char *chars = new char[100];
    std::cout << "chars = " <<
        static_cast<void *>(chars)
    << std::endl;
}

int main(){

    showAddress();
}

出力(Mac上のXcodeでビルドし実行)

$ ./ShowAddress
vec   = 0x7fff5fbff6e8
data  = 0x100400100
chars = 0x100400170

vector オブジェクトはスタック上に、vector内部で確保されるバッファとnewで確保したオブジェクトは別のメモリ領域に確保されている様子がみえます。

[C++] ファイルを読み込んでstd::stringを得る

テキストファイルからstd::stringを得るコードです。
ファイルサイズ分のメモリを一度に確保するので大きなサイズのファイルの読み込みには向きません。


#include <iostream>
#include <fstream>
#include <vector>

std::string getStringFromFile(const std::string& filePath) {
    
    std::ifstream ifs(filePath, std::ios::binary);
    
    // ファイルサイズを得る
    ifs.seekg(0, std::ios::end);
    size_t sz = ifs.tellg();
    ifs.seekg(0, std::ios::beg);
    
    //ファイルサイズ分ファイルから読み込む
    std::vector<char> buf(sz);
    ifs.read(buf.data(), sz);
    
    //読み込んだcharデータからstringを作成
    return std::string(buf.data(), sz);
}

int main() {
    
    std::string str = getStringFromFile("/var/tmp/note.txt");    
    std::cout << str << std::endl;
}

出力結果

$ echo "こんにちは、世界!" >> /var/tmp/note.txt
$ ./GetStrigFromFile
こんにちは、世界!

[C++] ファイルサイズの取得

ディスク上のファイルのファイルサイズを取得するサンプルコードです。

#include <iostream>
#include <fstream>

int main () {
    
    std::ifstream ifs("/var/tmp/data.xml");
    ifs.seekg(0, std::ios::end);
    std::ifstream::pos_type end = ifs.tellg();
    std::cout
        << std::to_string(end)
        << " bytes "
        << std::endl;
    return 0;
}

出力結果

$ ./GetFileSize
5976576 bytes 

[C++] バイト単位のファイルサイズを単位文字付きで表示する

バイト単位のサイズをログファイルや標準出力に出力する場合に分かりやすいように適切な単位(MB,GBなど)で表示するためのサンプルコードです。

#include <iostream>

struct SizeUnit {
    
    size_t factor;
    std::string unitStr;
};

const static SizeUnit NONE = { 1, "bytes" };
const static SizeUnit KILO = { 1024, "KB" };
const static SizeUnit MEGA = { KILO.factor * 1024, "MB" };
const static SizeUnit GIGA = { MEGA.factor * 1024, "GB" };
const static SizeUnit TERA = { GIGA.factor * 1024, "TB" };


const static int BUFSIZE = 100;

std::string format(const size_t sz, SizeUnit sizeUnit) {

    char buf[BUFSIZE];
    std::string fmt = sz % sizeUnit.factor == 0 ? "%.0f %s" : "%.1f %s";
    
    std::snprintf(
        buf, BUFSIZE, fmt.data(),
        static_cast<double>(sz)/static_cast<double>(sizeUnit.factor),
        sizeUnit.unitStr.data());

    return std::string(buf);
}

std::string getFormattedNumber(const size_t sz){

    if( sz > TERA.factor) {
        return format(sz, TERA);
    } else if( sz > GIGA.factor) {
        return format(sz, GIGA);
    } else if (sz > MEGA.factor) {
        return format(sz, MEGA);
    } else if (sz > KILO.factor) {
        return format(sz, KILO);
    } else {
        return format(sz, NONE);
    }
}

int main() {
    
    std::cout
        << getFormattedNumber(234) << std::endl
        << getFormattedNumber(34543) << std::endl
        << getFormattedNumber(345387320) << std::endl
        << getFormattedNumber(275123793035) << std::endl
        << getFormattedNumber(31038852073273) << std::endl;
}

出力結果はこちら

$ ./GetformattedNumber
234 bytes
33.7 GB
329.4 MB
256.2 GB
28.2 TB

[C++] call_onceを使ってある処理を一回だけ実行する

初期化処理などある処理を一度だけ呼び出して以降は呼び出さなくするやり方

以下の例ではSomeFunc()という関数の呼び出しの際に最初の一度だけinit()という関数を呼び出したい場合の例です。

#include <iostream>
#include <mutex>

void init (const int num) {
    
    std::cout << "init(" << std::to_string(num) << ") called" << std::endl;
}

void SomeFunc() {
    
    static std::once_flag flag;
    std::call_once(flag, init, 10);

    std::cout << "SomeFunc() called" << std::endl;
}

int main() {
    
    SomeFunc();
    SomeFunc();
    SomeFunc();    
}

SomeFunc() 関数にstaticな変数flagを持たせて、call_onceでinit()関数を呼び出すかどうかのチェックをしています。
実行結果は以下の通り

init(10) called
SomeFunc() called
SomeFunc() called
SomeFunc() called

SomeFunc()は3回呼ばれていますが、SomeFunc()の中でcall_once()経由で呼び出されるinit()は一度しか呼び出されていないのが分かります。

[C++] Visual Studioでコンパイル時間を表示する

Visual Studioでビルドした際にコンパイルやリンクなどの各処理時間とトータルのビルド時間を出力するための設定です。

  1. TOOLS → Options → Projects and Solutions → VC++ Project Settingsに移動
  2. Building TimingをYesに変更(デフォルトはNo)
  3. OK

これでビルドを実行したさいに各ビルド処理毎の処理時間とトータル時間が表示されるようになります。

1>------ Build started: Project: MyProject, Configuration: Release Win32 ------
1>  MyProject.cpp
1>  Generating code
1>  1 of 2048 functions ( 0.0%) were compiled, the rest were copied from previous compilation.
1>    0 functions were new in current compilation
1>    0 functions had inline decision re-evaluated but remain unchanged
1>  Finished generating code
1>  MyProject.vcxproj -> C:\Users\kazuyoshi_aizawa\documents\visual studio 2015\Projects\MyProject\Release\MyProject.exe
1>  MyProject.vcxproj -> C:\Users\kazuyoshi_aizawa\documents\visual studio 2015\Projects\MyProject\Release\MyProject.pdb (Full PDB)
1>
1>Project Performance Summary:
1>     6281 ms  C:\Users\kazuyoshi_aizawa\documents\visual studio 2015\Projects\MyProject\MyProject\MyProject.vcxproj   1 calls
1>               6281 ms  Build  #ビルド時間                1 calls
1>
1>Target Performance Summary:
1>        0 ms  AfterBuildCompileEvent                     1 calls
   ...略...
1>        3 ms  PrepareForBuild                            1 calls
1>        4 ms  FinalizeBuildStatus                        1 calls
1>        8 ms  InitializeBuildStatus                      1 calls
1>       12 ms  SetCABuildNativeEnvironmentVariables       1 calls
1>     2473 ms  Link  #リンク時間                           1 calls
1>     3751 ms  ClCompile  #コンパイル'時間                  1 calls
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

[C++] プリコンパイルヘッダでビルド時間を短縮する

C++で開発するときにBoostを利用することも多いとおもうのですけど、Boostを利用するとビルド時間がかかるようになって大変です。何十ものソースコードで構成されたプロジェクトなんかで再ビルドしたときなんかはそのビルド時間に辟易してしまいます。

そこで役に立つのがプリコンパイ済みヘッダ(precommpiled header)です。プリコンパイル済みヘッダを利用するとコンパイル時間を大幅に短くできます。

Visual Studio 2015で新規のC++プロジェクトを作成した場合、デフォルトでプリコンパイル済みヘッダを利用するように設定されています。もし設定されているかどうか不安な場合には以下で確認できます。

プロジェクトの設定確認

  1. プロジェクト名を右クリックしPropertiesを選択、Project Property Pageを表示
  2. Configuration Property → C/C++ → Precompiled Header
  3. Precompile Header が “Use (/Yu)“となっているのを確認。
  4. Precompile Header File は “stdafx.h”(デフォル)
  5. Precompiled Header Ouput File は”$(IntDir)$(TargetName).pch”(デフォルト)

プレコンパイル用のファイルのプロパティの確認

こちらもプロジェクト作成時に自動的に作成されているはずですが念のため確認します。

  1. Header Filesに stdafx.h というヘッダファイルがあるのを確認する。なければ追加。この時点では空ファイルでもいい。
  2. Source Filesに stdafx.cppというソースファイルがあるのを確認。なければ追加。内容は以下のとおり。
    #include "stdafx.h"
  3. stdafx.cppを右クリックしてのPropertiesを選択しプロパティウィンドを開く
  4. Configuration Property → C/C++ → Precompiled Header
  5. Precompile Header が “Create (/Yc)“となっているのを確認。上の設定と違うので注意。

プレコンパイルするヘッダの指定

とりあえずプロジェクト側の設定は終わりました。(デフォルトで設定されてますが)
実際に以下のようなBoostをつかったコードをコンパイルしてみることにします。

#include "stdafx.h"
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;boost/thread/future.hpp&amp;gt;

void printHelloTask() {
	std::cout &amp;lt;&amp;lt; "Hello" &amp;lt;&amp;lt; std::endl;
}

int main() {

 	boost::unique_future&amp;lt;void&amp;gt; f1 =
 		boost::async(boost::launch::async, printHelloTask);
}

これをこのままコンパイルすると3秒かかります。

1>------ Build started: Project: MyProject, Configuration: Release Win32 ------
1>  MyProject.cpp
1>  Generating code
...
1>     3722 ms  ClCompile                                  1 calls
1>     3941 ms  Link                                       1 calls
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

※Visual Studioでビルド時間を表示するように変更するにはVisual Studioコンパイル時間を表示するを参照してください。

プレコンパイルするヘッダを指定する

時間がかかるヘッダをstdafx.hヘッダに追加します。ソースファイルのstdafx.cppの方ではないのでお間違いなく。
ここでは<boost/thread/future.hpp>を指定します。


#include <boost/thread/future.hpp>

ソース・ファイルのプロパティの確認

実際のプログラムを記載したソースファイルを作成すれば自動的に上で上記で作成されたプレコンパイル済みヘッダを利用することになっているはずですが、念のためソース・ファイルのプロパティを確認してプレコンパイル済みヘッダを使うようになっているか確認してみましょう。

  1. ソースファイル(MyProject.cpp)を右クリックしてのPropertiesを選択しプロパティウィンドを開く
  2. Configuration Property → C/C++ → Precompiled Header
  3. Precompile Header が “Use (/Yu)“となっているのを確認。こちらはまた Use です。

 

これで準備が終わったので再度コンパイルしてみます。

 

1>------ Build started: Project: MyProject, Configuration: Release Win32 ------
1>  MyProject.cpp
1>  Generating code
...
1>      593 ms  ClCompile                                  1 calls
1>     1903 ms  Link                                       1 calls
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

4秒近くかかっていたものが600ms程度(6倍)になりました! ソースファイルが多くなればなるほど効果が大きいのがおわかりになると思います。
ちなみにプレコンパイルヘッダ指定後最初のコンパイル時にはstdafx.cppがビルドされプレコンパイルヘッダ自身(*.pch)が作成されるのでこれには時間がかかります。以降のコンパイル時にはプレコンパイル済みヘッダが使われるのでソース・ファイル(MyProject.cpp)のコンパイルは早くなります。

[C++] std::sortに渡すソート条件を指定する比較関数 (Compare Function)

自分が作ったクラスをベクターなどに格納しそれらを指定の任意の条件でソートしたい場合があると思います。 std::sortはこのソートの条件に使う比較関数オブジェクトを受け取ってそれに従ってソートしてくれます。

比較関数は二つのオブジェクトを引数にとり最初に引数が2番めの引数より小さい時にtrueを返すようにします。(昇順でソートする場合)

文字列の長さ順位ソートする場合の比較関数

bool comp(const std::string& lh, const std::string& rh) {
     // 文字列lhの長さが文字列rhより短かったらtrueを返す
     return lh.length() < rh.length();
}

関数ではなくoperator()を実装したクラスとして宣言し、そのオブジェクトを渡すこともできます。

operator()をもったクラスとして実装する場合


class Comp {
public:
    bool operator() (const std::string& lh, const std::string& rh) {</pre>

     // 文字列lhの長さが文字列rhより短かったらtrueを返す
    return lh.length() < rh.length();
    }
}; 

文字列のリストを長さ順でソートする例


#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

bool comp(const std::string& lh, const std::string& rh) {
    
    return lh.length() < rh.length();
}

class Comp {
public:
    bool operator() (const std::string& lh, const std::string& rh) {

        return lh.length() < rh.length();
    }
};

int main () {

    std::vector<std::string> strs {
        "clock",
        "factory",
        "industrialization",
        "skyscraper",
        "sun"
    };

    // 二つの引数をうけとりboolを返す関数を渡す場合
    std::sort(strs.begin(), strs.end(), comp);
    for(const std::string& str : strs) {
        
        std::cout << str << std::endl;
    }

    std::cout << std::endl;

    // operator() を持ったクラスのオブジェクトを渡す場合
    std::sort(strs.begin(), strs.end(), Comp());    
    for(const std::string& str : strs) {
        
        std::cout << str << std::endl;
    }
}

実行結果

sun
clock
factory
skyscraper
industrialization

sun
clock
factory
skyscraper
industrialization

ラムダ式でソートの条件を指定する場合

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector < std::string> words{ "12345", "12", "123456", "123" };

    std::sort(words.begin(), words.end(), [](const std::string& lh, const std::string& rh) {
        return rh.length() > lh.length(); });

    for (const std::string str : words)
    {
        std::cout << str << std::endl;
    }
}

実行結果

12
123
12345
123456