20210106のMacに関する記事は7件です。

Mac Catalystでのキーボードイベントについて 【Xcode & Swift】

はじめに

今回の記事は、例えば電卓アプリを作成する場合、表示ラベル、数字キーと演算(+/-/×/÷/=)キーボタンを配置して、ボタンタップやマウスクリックで操作するシーンは普通であるが、ここに物理キーボードのキー押下でも、操作したい場合の話である。(テキスト入力フィールドを持つアプリであれば、特に何も困らないので。)
また、同一ソースコードでiOS(含むiPadOS)とMacOS(Mac Catalyst)の全部に対応したい場合の話である。

記事執筆時点の環境は以下の通り。

開発環境version
- MacOS : 11.1 (20C69)
- Xcode : 12.3 (12C33)
- Swift : 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)

ターゲット環境version
- iOS/iPadOS : 14.0
- MacOS : 11.0

1. キーボードイベントの拾い方

APPKitによるMacOSアプリの場合は、NSViewクラスのkeyDown(with:)keyUp(with:)メソッドを実装すれば良いが、このメソッドはUIViewクラスには存在しない。
UIKitだとUIViewクラスのpressesBegan(:with:)pressesEnded(:with:)メソッドを実装することになるが、UIKitネイティブのiOS/iPadOSなら問題なく動作するが、Mac(Catalyst)だと一部のキーは動作するがほとんどのキーはコンソールに「Warning: insertText reached」が出力され上記メソッドは呼ばれない。こちらの記事 1 と似たような現象だが解決されてない。

他の方法としては、iOS14からサポートされたGame ControllerによるGCKeyboardクラスを使用する方法がある。 使い方の概要は以下の通り。

if let keyboard = GCKeyboard.coalesced?.keyboardInput {
    // bind to any key-down/up
    keyboard.keyChangedHandler = {
        (keyboard, key, keyCode, pressed) in
        // compare button to GCKeyCode
        ・・・
    }

    // bind to specific key-down/up
    keyboard.button(forKeyCode: .spacebar)?.valueChangedHandler = {
        (key, value, pressed) in
        // SpaceBar was pressed or released
        ・・・
    }
}

試した限り、GCKeyboardクラスを使用すれば、iOS/iPadOSとMac(Catalyst)の全部で動作した。
ただし、Macについては、一部のキー押下でBeep音が出る現象に遭遇した。これは、APPKitによるMacOSアプリでNSViewクラスのkeyDown(with:)keyUp(with:)メソッドを実装した時に発生した現象と同じであるが、MacAppでの回避策 2 3 4NSViewを使わないMac(Catalyst)では適用できない。

2. Beep音回避

Mac(Catalyst)でGCKeyboard使った時のBeep音の回避策はズバリ、ここ 5 に載っていた。
pressesBegan pressesEndedをダミー実装してアプリケーションレベルにメッセージを伝達させないことである。心配なのでpressesCancelledもダミー実装した。

override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) { }
override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) { }
override func pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?) { }

3. GCKeyCodeのハンドリング

GCKeyboardクラスによるキーボードイベントのハンドリングは、非常にローレベルなハンドリングとなる。どのキーが押されたのか/離されたのかがGCKeyCode型で通知されるが、この型はキーボードのキートップの刻印とは必ずしも一致しないので、注意が必要である。

いくつか例を示す。

・ イコール記号(=)

JISキーボードだと shiftキーと-(ハイフン)キー であるため、leftShift(rightShift)とhyphenの2回のイベントに別れて通知される。
USキーボードだと =(イコール)キー であるため、equalSignの1回のイベントで通知される。

つまり、同じ文字でもJIS/USキーボードで通知されるコードが違うことがある。左右の2つのシフトキーは区別され独立して通知される。

・ 数字のゼロ(0)

普通はキーボード上部に数字キーは並ぶが、フルキーボードだと右側にテンキーとしても数字キーが配置され、同じ0(数字のゼロ)でもコードが違う。
キーボード上部の数字0はzero。テンキーの数字0はkeypad0。 余談であるが、個人的にはzeroではなく、アルファベットと同じようにkey0として欲しかった。

つまり、同じキートップ文字でも、キーの場所が違うと通知されるコードが違う。

・ aとA(小文字/大文字)の扱い

CapsLockされていない限り、英文字は小文字で入力されるのが普通である。大文字で入力する場合はシフトキーと同時に押す。一方、CapsLockされている場合は、大文字で入力され、シフトキーと同時に押すと小文字になる。
シフトキーAの場合に、大文字と解釈するのか小文字と解釈するのか、CapsLockの状態に依存するが、これを知ることができるのか不明である。英小文字と大文字を区別したいアプリの場合はこのハンドリングが難しいだろう。
(アプリ起動後のCapsLockキー押下はイベント通されるが、アプリ起動前にすでにCapsLock状態の場合だと、逆の意味となる)

UIKey型であればmodifierFlagsによってCapsLock状態を知ることができるので、pressesBeganイベントを併用すれば判断が可能か? (試してないので併用できるか不明) (2021.1.7追記)
pressesBeganイベントを併用できることを検証したが、それでも工夫が必要である。

pressesBeganイベントの併用における注意点

iOSとMac(Catalyst)で挙動が異なる。OSのバグの可能性もあるので検証時のバージョンを明示しておく。
- MacOS 11.1(20C69)
- iOS 14.2 (18B92)

メソッドの呼び出し(順)

  • Mac Catalyst
# メソッド Aキーのみ シフトキーのみ シフトキーAキー 備考
1 keyChangedHandler pressed=true 1 1 1 (s), 3 (a) (s)シフトキー
2 keyChangedHandler pressed=false 2 3 4 (a), 5 (s) (a)Aキー
3 pressesBegan - 2 2 (s)
4 pressesEnded - 4 6 (s)

AキーにおいてpressesBegan/pressesEndedが呼ばれないのは、1項で説明した通り。

  • iOS
# メソッド Aキーのみ シフトキーのみ シフトキーAキー 備考
1 keyChangedHandler pressed=true 2 2 2 (s), 4 (a) (s)シフトキー
2 keyChangedHandler pressed=false 4 4 6 (a), 8 (s) (a)Aキー
3 pressesBegan 1 1 1 (s), 3(a)
4 pressesEnded 3 3 5 (a), 7(s)

keyChangedHandlerpressesBegan(/Ended)が呼ばれる順がMac(Catalys)と逆になる。

CapsLockキーの扱い

# キーの押下順 Mac iOS CapsLock状態を示すLED
0 - - -  消灯
1 CapsLockキーを押す pressed=true, PressesBeganが呼ばれる PressesBegan, pressed=trueが呼ばれる 点灯
2 CapsLockキーを離す 何も呼ばれない PressesEended, pressed=falseが呼ばれる 点灯
3 Aキーを押す pressed=trueが呼ばれる PressesBegan, pressed=trueが呼ばれる 点灯
4 Aキーを離す pressed=falseが呼ばれる PressesBegan, pressed=trueが呼ばれる 点灯
5 CapsLockキーを押す pressed=false, PressesEendedが呼ばれる PressesBegan, pressed=trueが呼ばれる  消灯
6 CapsLockキーを離す 何も呼ばれない PressesEended, pressed=false  消灯

PressesBeganに渡されるUIPress.key.modifierFlagsalphaShiftがCapsLock状態を示す為、アプリ起動後のCapsLock状態はMac/iOSとも、正しく認識可能である。
しかし、アプリ起動前にCapsLock状態にしておいた場合は、Mac/iOSとも、正しくCapsLock状態を認識できない。理由は、Macの場合、AキーでPressesBeganが呼ばれない為。iOSの場合、UIPress.key.modifierFlagsalphaShiftが真逆にセットされている為である。iOSはバグの可能性がある。

・ キーボード自体の識別

JISとUSキーボードではキー配列に大きな違いがあるが、JISキーボードのキーが押されたのか、USキーボードのキーが押されたのか、これを区別する方法は未調査である。 これを区別できない。(2021.1.8追記)
GCPhysicalInputProfileでキー数等は判別できるが、明確にキーボードの種類を識別できる情報は無い。そもそもJISキーボードでハイフンの右隣のキー^(ハット)を押すと、なんとequalSignを返してくる。これはUSキーボード配列のコードである。

keyboard.png

電卓アプリ程度であれば使用するキーが限定的なため上記の点だけを注意すれば実現可能であるが、viの様なスクリーンエディタを開発するとなると、キーボードイベントのハンドリングに相当な労力が必要と思われる。

4. Macキーボードの例

Apple純正キーボードのキー配列は以下の通り。

JISキーボード
JISキーボード

USキーボード
USキーボード

最後に

『Mac(Catalyst)でキーボードイベントが拾えない。キーを叩くとBeep音が出る。』この調査にほぼ一日を要したので、ここにまとめておいた。未調査/未検証事項は後日必要時に追記することとする。 (2021.1.8追記)
そもそもGame Controllerはゲームアプリのためのフレームワークであるから、これでviの様なスクリーンエディタを開発しようとすること自体に無理があるのだろう。
以上

おまけ

UIKeyModifierFlagsGCKeyCodeを可視化(文字化)するエクステンションを載せておく。

ここに表示
extension UIKeyModifierFlags {
    var toString: String {
        var result = "["
        let keys: [UIKeyModifierFlags] = [.alphaShift, .shift, .control, .alternate, .command, .numericPad]
        let strs = ["alphaShift", "shift", "control", "alternate", "command", "numericPad"]
        for n in keys.indices {
            if self.contains(keys[n]) {
                if result.count == 1 {
                    result += strs[n]
                } else {
                    result += " ," + strs[n]
                }
            }
        }
        result += "]"
        return result
    }
}

extension GCKeyCode {
    var toString: String {
        let str: String
        switch self {
        case .F1: str = "F1"
        case .F10: str = "F10"
        case .F11: str = "F11"
        case .F12: str = "F12"
        case .F2: str = "F2"
        case .F3: str = "F3"
        case .F4: str = "F4"
        case .F5: str = "F5"
        case .F6: str = "F6"
        case .F7: str = "F7"
        case .F8: str = "F8"
        case .F9: str = "F9"
        case .LANG1: str = "LANG1"
        case .LANG2: str = "LANG2"
        case .LANG3: str = "LANG3"
        case .LANG4: str = "LANG4"
        case .LANG5: str = "LANG5"
        case .LANG6: str = "LANG6"
        case .LANG7: str = "LANG7"
        case .LANG8: str = "LANG8"
        case .LANG9: str = "LANG9"
        case .application: str = "application"
        case .backslash: str = "backslash"
        case .capsLock: str = "capsLock"
        case .closeBracket: str = "closeBracket"
        case .comma: str = "comma"
        case .deleteForward: str = "deleteForward"
        case .deleteOrBackspace: str = "deleteOrBackspace"
        case .downArrow: str = "downArrow"
        case .eight: str = "eight"
        case .end: str = "end"
        case .equalSign: str = "equalSign"
        case .escape: str = "escape"
        case .five: str = "five"
        case .four: str = "four"
        case .graveAccentAndTilde: str = "graveAccentAndTilde"
        case .home: str = "home"
        case .hyphen: str = "hyphen"
        case .insert: str = "insert"
        case .international1: str = "international1"
        case .international2: str = "international2"
        case .international3: str = "international3"
        case .international4: str = "international4"
        case .international5: str = "international5"
        case .international6: str = "international6"
        case .international7: str = "international7"
        case .international8: str = "international8"
        case .international9: str = "international9"
        case .keyA: str = "keyA"
        case .keyB: str = "keyB"
        case .keyC: str = "keyC"
        case .keyD: str = "keyD"
        case .keyE: str = "keyE"
        case .keyF: str = "keyF"
        case .keyG: str = "keyG"
        case .keyH: str = "keyH"
        case .keyI: str = "keyI"
        case .keyJ: str = "keyJ"
        case .keyK: str = "keyK"
        case .keyL: str = "keyL"
        case .keyM: str = "keyM"
        case .keyN: str = "keyN"
        case .keyO: str = "keyO"
        case .keyP: str = "keyP"
        case .keyQ: str = "keyQ"
        case .keyR: str = "keyR"
        case .keyS: str = "keyS"
        case .keyT: str = "keyT"
        case .keyU: str = "keyU"
        case .keyV: str = "keyV"
        case .keyW: str = "keyW"
        case .keyX: str = "keyX"
        case .keyY: str = "keyY"
        case .keyZ: str = "keyZ"
        case .keypad0: str = "keypad0"
        case .keypad1: str = "keypad1"
        case .keypad2: str = "keypad2"
        case .keypad3: str = "keypad3"
        case .keypad4: str = "keypad4"
        case .keypad5: str = "keypad5"
        case .keypad6: str = "keypad6"
        case .keypad7: str = "keypad7"
        case .keypad8: str = "keypad8"
        case .keypad9: str = "keypad9"
        case .keypadAsterisk: str = "keypadAsterisk"
        case .keypadEnter: str = "keypadEnter"
        case .keypadEqualSign: str = "keypadEqualSign"
        case .keypadHyphen: str = "keypadHyphen"
        case .keypadNumLock: str = "keypadNumLock"
        case .keypadPeriod: str = "keypadPeriod"
        case .keypadPlus: str = "keypadPlus"
        case .keypadSlash: str = "keypadSlash"
        case .leftAlt: str = "leftAlt"
        case .leftArrow: str = "leftArrow"
        case .leftControl: str = "leftControl"
        case .leftGUI: str = "leftGUI"
        case .leftShift: str = "leftShift"
        case .nine: str = "nine"
        case .nonUSBackslash: str = "nonUSBackslash"
        case .nonUSPound: str = "nonUSPound"
        case .one: str = "one"
        case .openBracket: str = "openBracket"
        case .pageDown: str = "pageDown"
        case .pageUp: str = "pageUp"
        case .pause: str = "pause"
        case .period: str = "period"
        case .power: str = "power"
        case .printScreen: str = "printScreen"
        case .quote: str = "quote"
        case .returnOrEnter: str = "returnOrEnter"
        case .rightAlt: str = "rightAlt"
        case .rightArrow: str = "rightArrow"
        case .rightControl: str = "rightControl"
        case .rightGUI: str = "rightGUI"
        case .rightShift: str = "rightShift"
        case .scrollLock: str = "scrollLock"
        case .semicolon: str = "semicolon"
        case .seven: str = "seven"
        case .six: str = "six"
        case .slash: str = "slash"
        case .spacebar: str = "spacebar"
        case .tab: str = "tab"
        case .three: str = "three"
        case .two: str = "two"
        case .upArrow: str = "upArrow"
        case .zero: str = "zero"
        default: str = "???"
        }
        return str
    }
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

M1搭載Macのpip installに苦戦した

参考記事
https://freeheroblog.com/pipenv-install/

M1搭載のMacBookProを買ったがpip install すら出来ず。
それを乗り越えたので。
難しいことはしてないし書かないし分からない。

環境

MacBookPro M1

つまづいた原因

Homebrew がARMプロセッサでは対応してないということで
インストールを諦めた事。

そもそも、普通にはインストール出来なかった

Homebrewインストール方法

特に気にせず、
ターミナルで

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

を実行すると、
「ARMプロセッサに対応してない」的なエラーが出る
と同時に下の文には、
「Rosetta2でHomebrewインストールを再実行します」
と書いてある

そのため、Rosettaからインストールしますがその方法を下記に。

①Finderからターミナルを検索します
②ターミナルを2本指クリック(右クリック)
③「情報をみる」をクリック
④「Rosetta」を使用して開く にチェックを入れる

ここまでしたら再度、ターミナルを開いて、

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

実行します

何かしら上手くいかなければPCを再起動してください
それで自分もインストールできました

ここまでできたら
仮想環境内であろうと、pip install が正常に動作するようになりました

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

.DS_Storeをコマンド一発で再帰的に消す

ファイル納品の時とか邪魔でしょうがないのでaliasを切ってカレント配下全部消すようにする。

.bashrcに以下追記

alias rmds='find . -name ".DS_Store" -print -exec rm {} ";"'

remove ds の略

.DS_Storeを消したいディレクトリに移動してrmdsするだけ。

新年一発目の記事、おわり。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#でProtocolBuffersを使って見た!!

?新年明けましておめでとうございます?

業務の中でProtocolBuffersを使用することになり、
"なんなんそれ..."と思い、習うより慣れろということで動かしてみました。
詳しい説明を知りたい方は先人の方々がわかりやすく解説してくださっているものが
ありますのでそちらを参考にしていただきたいと思います。
ちなみに、私はこちらのページを参考にしました。

手順の流れ

  1. Protocを入手
  2. Protoファイル作成
  3. ProtoファイルからC#のクラスを自動生成する
  4. サンプルプログラムを書く

1. Protocを入手

Homebrewを使用して入手

# terminal
$ brew update     # formula を更新
$ brew upgrade    # 更新があるパッケージを再ビルドする
$ brew install protobuf # protobufをインストール
$ brew upgrade protobuf # protobufをアップグレード

$ protoc --version
libprotoc 3.14.0

2. Protoファイル作成

Human.proto
syntax = "proto3";
package MyPackage;

message Human {
  string name = 1;
  uint32 age = 2;
}

3. ProtoファイルからC#のクラスを自動生成する

・Protoファイルが存在する場所まで移動する。

# terminal
protoc --csharp_out=. -I. Human.proto

4. サンプルプログラムを書く

下準備

・NuGetから Google.Protobuf をインストールする。
・先程の自動生成したcsファイルをRiderのProgram.csと同じ階層に置く。

Program.cs
using System;
using Google.Protobuf;
using MyPackage;

namespace protocol_test
{
    class Program
    {
        static void Main(string[] args)
        {
            var human = new Human
            {
                Name = "name001",
                Age = 20
            };

            byte[] bytes = human.ToByteArray();
            Console.WriteLine(BitConverter.ToString(bytes)); // 

            // デシリアライズ
            var human2 = new Human();
            human2 = Human.Parser.ParseFrom(bytes);

            Console.WriteLine(human2.Age);
        }
    }
}
#実行結果
0A-07-6E-61-6D-65-30-30-31-10-14
20

参考文献

C#でProtocolBuffersを使う方法
Protocol Buffers 導入メモ Mac/Win
XML、JSON、Protocol Buffersを比較してみました

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デベロッパーツールへの行き方2通り

  1. alt + command + i

  2. 特定の要素を右クリック+検証を押下
    →デベロッパーモードが開き、特定の要素のHTMLがデベロッパーモードに現れる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【mac】gethのデータを外付けSSDへ移行【ストレージ不足解消】

はじめに

macのストレージがカツカツになりました。
ストレージ不足のせいでXcodeのアップデートができない困った状況です…。
ss01
でも、私の環境における諸悪の根源はわかっています。
EthereumDApps作業用に使っているgethのデータディレクトリです。
ss02
rinkebyディレクトリだけで78GBも喰っています…。
こいつをなんとかしてストレージ不足を解消することにしました。

で、試行錯誤の結果、gethのデータを外付けSSDへ移行できたので、その際の手順をメモしておきます。

環境

私の環境は下記となります。

PCMacBook Air(13-inch, Early 2014)
OSCatalina(10.15.6)
HD256GB(フラッシュストレージ)

gethのバージョン:1.9.9

外付けSSDSanDisk Extreme ポータブル SSD(250GB)
※ヨドバシで8800円でした

では、手順を見ていきましょう。

外付けSDDの形式確認/フォーマット

外付けSSDWindowsパソコンと共有できたら便利なので互換性のあるexFATにしたい所ですが、私の環境ではgethの起動時に下記のエラーがでて同期できませんでした。

exFATで発生したエラー
Fatal: Error starting protocol stack: listen unix /Volumes/ssd_drive/geth/rinkeby/geth.ipc: bind: invalid argument

ですので、外付けSSDのフォーマットはAPFSにしました。
※すでに外付けSSDAPFSでフォーマットされている場合は、下記の手順.2(フォーマット)はスキップしてください
※途中まで試した感じだと[Mac OS拡張(ジャーナル)]でも動きそうな感じはしましたが、最後までは試していません

手順.1:ディスクユーティリティの起動

外付けSSDmacに接続して[Launcpad]→[その他]→[ディスクユーティリティ]を起動します。

手順.2:外付けSSDのフォーマット

*ご注意*
以下の手順を試す際は、間違ってmacのHDをフォーマットしないように、対象のドライブが外付けのSSDになっているかをよく確認した上で行ってください

対象の外付けSSDを右クリックして[消去...]を選択します。
ss03
開いたダイアログにて、フォーマットを[APFS]に設定して、[消去]を実行します。
(※APFSが表示されない場合/エラーがでる場合は後述の[補足:APFSの設定がうまくいかない場合]を参照ください
(※セキュリティオプションで[最も安全]を選ぶと時間がかかるのでご注意ください=試しにやったら日が暮れました…
ss04

補足:APFSの設定がうまくいかない場合

case.1
APFSが選択できない場合は、一旦[Mac OS拡張(ジャーナル)]形式で消去した後、対象のSSDを右クリックしたメニューから[APFSに変換...]を選択します。
ss06

case.2
APFS変換時に「A GUID Partition Table (GPT) partitioning scheme is required.」エラーがでる場合は[diskutil]にて初期化します。

まず、[ターミナル]を起動します。

続いて、下記のコマンドにて外付けSSDのディスク番号を確認します。

ディスク番号を確認する
 $ diskutil list

*実行例*

[MacBook-Air:~ hakumai$ diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME > SIZE IDENTIFIER
0: GUID_partition_scheme *251.0 GB disk0
1: EFI EFI > 209.7 MB disk0s1
2: Apple_APFS Container disk1 250.8 GB disk0s2

/dev/disk1 (synthesized):
#: TYPE NAME > SIZE IDENTIFIER
0: APFS Container Scheme - +250.8 GB disk1
Physical Store disk0s2
1: APFS Volume Macintosh HD - Data 221.2 GB disk1s1
2: APFS Volume Preboot 82.3 MB disk1s2
3: APFS Volume Recovery 528.8 MB disk1s3
4: APFS Volume VM 1.1 GB disk1s4
5: APFS Volume Macintosh HD 11.1 GB disk1s5

/dev/disk2 (external, physical):
#: TYPE NAME > SIZE IDENTIFIER
0: GUID_partition_scheme *250.1 GB disk2
1: EFI EFI 209.7 MB disk2s1
2: Microsoft Basic Data 名称未設定 249.8 GB disk2s2

↑ 私の環境では、外付けSSDが[disk2]として認識されていました。

ディスク番号がわかったら、下記のコマンドにて外付けSSDをフォーマットします。

対象のディスクをAPFSでフォーマットする
 $ diskutil eraseDisk APFS [設定するドライブ名] [対象のディスク番号]

*実行例*

[MacBook-Air:~ hakumai$ diskutil eraseDisk APFS ssd_drive disk2
Started erase on disk2
Unmounting disk
Creating the partition map
Waiting for partitions to activate
Formatting disk2s2 as APFS with name ssd_drive
Mounting disk
Finished erase on disk2

↑ドライブ名を[ssd_drive]、ディスク番号を[disk2]でフォーマットした例です。

case.3
[diskutil]の[APFS]指定で失敗する場合は、オプション[JHFS+](Mac OS拡張)で初期化し、その後[case.1]の手順をお試しください。

対象のディスクをJHFS+でフォーマットする
 $ diskutil eraseDisk JHFS+ [設定するドライブ名] [対象のディスク番号]

手順.3:ドライブ名の設定

ドライブ名をクリックしてお好きな名前をつけましょう。
ここでは[ssd_drive]としました。
ss05
gethの同期時に、このドライブ名でパスを指定することになります。
例えば上記例であれば、パスは[/Volumes/ssd_drive]となります。

gethで同期

外付けSSDに適当なディレクトリを作成してgethの同期を開始します。
(※ここでは接続先をRinkebyテストネットとしています
(※外付けSSDに作成した[geth/rinkeby]ディレクトリを保存先にしたいので、パスとして[/Volumes/ssd_drive/geth/rinkeby]を指定しています

gethで同期
 $ geth --rinkeby --datadir /Volumes/ssd_drive/geth/rinkeby

↓同期中、retryが出まくったのでかなりドキドキしました(※外付けSSDへの書き込みが遅いせいかもしれません…)。

count=1920 elapsed=10.325ms processed=163021371 pending=6704 retry=0 duplicate=18423 unexpected=60488
INFO [01-06|08:37:07.173] Imported new state entries count=1920 elapsed=12.420ms processed=163023291 pending=5893 retry=0 duplicate=18423 unexpected=60488
INFO [01-06|08:37:07.927] Imported new state entries count=1536 elapsed=8.910ms processed=163024827 pending=5925 retry=0 duplicate=18423 unexpected=60488
INFO [01-06|08:37:08.735] Imported new state entries count=1536 elapsed=8.045ms processed=163026363 pending=6121 retry=0 duplicate=18423 unexpected=60488
INFO [01-06|08:37:09.517] Imported new state entries count=1536 elapsed=9.212ms processed=163027899 pending=5965 retry=0 duplicate=18423 unexpected=60488
INFO [01-06|08:37:10.249] Imported new state entries count=1920 elapsed=11.310ms processed=163029819 pending=5222 retry=0 duplicate=18423 unexpected=60488
INFO [01-06|08:37:10.916] Imported new state entries count=1536 elapsed=9.066ms processed=163031355 pending=4988 retry=0 duplicate=18423 unexpected=60488

ですが、ひたすら放置しておいたら、同期が完了してくれました。
↓下記のログが出力されたら同期の完了です(※gethを終了するには[Ctrl+C]を入力します)。

INFO [01-06|08:59:34.821] Fast sync complete, auto disabling

同期にかかった時間は24時間弱、ほぼ丸一日でした。

感覚的にはmacHD(フラッシュストレージ)を対象にした時に比べて、2〜3倍遅い印象です。
mac側のコネクタがType-Aなので、Type-Cの利用できるmacならもっと速いのではないかと思います。

truffleとの連携確認:読み込み

同期したデータディレクトリを対象にgethRPCモードで起動します。

gethをPRCモードで起動
$ geth --allow-insecure-unlock --rpc --rpcapi personal,web3,eth,net --verbosity 0 console --rinkeby --datadir /Volumes/ssd_drive/geth/rinkeby

次に、ターミナルの別タブからTruffleを起動します
※rinkebyのネットワーク設定がされているプロジェクトフォルダへ移動してから起動してください

Truffleの起動
$ truffle console --network rinkeby

テストアカウントの残高を確認します(※残高表示が0だったり実際の値と違う場合は同期が完了していないので再同期してください)。

残高確認
truffle(rinkeby)> web3.eth.getBalance( accounts[0] )
'474167714324901098982'

MetaMask等で残高を増減した後、再度残高を確認します(※ここでは[0.16ETH]減らしてみました)。

再度残高確認
truffle(rinkeby)> web3.eth.getBalance( accounts[0] )
'474005299324901098982'

ちゃんと同期がとれています。

[truffle]との連携確認:デプロイ

スマートコントラクトをデプロイしてみます。
※プロジェクトのビルドが通り、migrateの設定に問題がない状況でデプロイしてください

コントラクトのデプロイ
[truffle(rinkeby)> migrate --f 2

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.

Migrations dry-run (simulation)
===============================
> Network name:    'rinkeby-fork'
> Network id:      4
> Block gas limit: 10000000 (0x989680)

2_deploy_contracts.js
=====================

   Replacing 'HelloWorld'
   ----------------------
   > block number:        7844413
   > block timestamp:     1609893660
   > account:             0xebfCB28c530a9aAD2e5819d873EB5Cc7b215d1E1
   > balance:             474.003238390901098982
   > gas used:            1030467 (0xfb943)
   > gas price:           2 gwei
   > value sent:          0 ETH
   > total cost:          0.002060934 ETH

   -------------------------------------
   > Total cost:         0.002060934 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.002060934 ETH

Starting migrations...
======================
> Network name:    'rinkeby'
> Network id:      4
> Block gas limit: 10000000 (0x989680)

2_deploy_contracts.js
=====================

   Replacing 'HelloWorld'
   ----------------------
   > transaction hash:    0xdf4bb76e2ca3913cd637cd7ceaeec0aafc409743493cf3fbb10c85249c7f2ec7
   > Blocks: 1            Seconds: 4
   > contract address:    0xaD1c3A4E6E19955C4a3cdB993843d7aC78F7294c
   > block number:        7844412
   > block timestamp:     1609893664
   > account:             0xebfCB28c530a9aAD2e5819d873EB5Cc7b215d1E1
   > balance:             473.984389984901098982
   > gas used:            1045467 (0xff3db)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.02090934 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:          0.02090934 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.02090934 ETH

デプロイも問題なく完了しました。
外部クライアントから適当にアクセスし、その結果もEthescanから確認できました。

https://rinkeby.etherscan.io/address/0xaD1c3A4E6E19955C4a3cdB993843d7aC78F7294c

どうやら問題なく動いているようです。
結果として、mac側のストレージから[geth]のデータディレクトリを削除することができました。
ss07
空き容量も100GBを回復して、Xcodeのアップデートも無事完了しました。

めでたしめでたし。

まとめ

gethの同期先を外付けSSDを対象にした場合、macHDと比べて同期に時間がかかるので、ストレージをとるか速さをとるかで検討しましょう。
たまにsolidityをいじってデプロイする程度のgeth利用であれば、データを外付けSSDへ移行するのは十分ありだと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity for Mac】VSCodeでC# Extensionの設定

UnityのScript EditorでVSCode

  • C# Extensionが機能しない
  • F12やCommand+クリックで関数の定義へジャンプしない
  1. C#のエクステンションをインストールする(エクステンションショートカット:Command+Shift+X)
  2. 設定を開く(設定ショートカット:Command+,)
  3. Search settingsに「mono」とタイプすると、Extensionsの項目に「C# configuration」がヒットするので開く
  4. 「Use Global Mono」の設定を「always」にする
  5. 「Mono Path」の設定(Edit in settings.json)を開き、「omnisharp.monoPath」を入力する
  6. VSCodeを再起動する

omnisharp.monoPath の確認方法

ターミナルを開き以下のコマンドで確認する

which mono

mono バージョンの確認方法

mono -V
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む