Xcodeで実機デバッグ試すとThis operation can fail if the version of the OS on the device is incompatible…と出る

Xcodeで実機デバッグを試みたところ、下記のエラーが発生しました

Failed to prepare device for development.

This operation can fail if the version of the OS on the device is incompatible with the installed version of Xcode. You may also need to restart your mac and device in order to correctly detect compatibility.

こちらの問題ですが、どうやらXcodeでバージョンの対応があるかないか?で判断してるようで、対応していないとエラーが出るみたいです

ちなみに対応しているかどうかは下記のコマンドで件検証可能

cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

ls
10.0	10.2	11.0	11.2	11.4	12.1	12.3	13.0	13.2	13.4	13.6	14.0	14.2	14.4	15.0	9.0	9.2
10.1	10.3	11.1	11.3	12.0	12.2	12.4	13.1	13.3	13.5	13.7	14.1	14.3	14.5	15.2	9.1	9.3

私が検証したいのは15.5で一覧にないので、下記のプロジェクトからpullして上記dirに移動させます

プロジェクトのURL

ダウンロードが完了したらターミナルで下記を実行していきます

# Downloads dirに移動
cd Downloads

# zipをunzip
unzip 15.5.zip
Archive:  15.5.zip
   creating: 15.5/
  inflating: 15.5/DeveloperDiskImage.dmg.signature
  inflating: 15.5/DeveloperDiskImage.dmg

# 解凍したdirをiOSバージョンのdirへ移動. 権限エラーが発生するのでsudoをつけてます
sudo mv 15.5 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

# 該当のdirへ移動して確認
cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
ls
10.0	10.2	11.0	11.2	11.4	12.1	12.3	13.0	13.2	13.4	13.6	14.0	14.2	14.4	15.0	15.5	9.1	9.3
10.1	10.3	11.1	11.3	12.0	12.2	12.4	13.1	13.3	13.5	13.7	14.1	14.3	14.5	15.2	9.0	9.2

15.5を入れた後は問題なく起動しました!

参考記事

filsv/iOSDeviceSupport

Xcode: iOS 15.4 実機ビルドができない!?

XcodeでimageLiteralが出てこない

Xcode 13.2.1でimageLiteralがサジェストで出てこなく、調べてみたら記述方法が変わったとのことです

class ViewController: UIViewController {
    @IBOutlet weak var hoge: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        hoge.image = #imageLiteral()
    }
}

#imageLiteralと記述し、その後に括弧を入れることで画像選択UIが発火します

参考記事

Color Literal behaves inconsistently in Xcode 13.2.1

[WIP]NeoVim + iOSでUIKitやSwiftUIの補完を可能にする

sourcekit lspを追加するところまでは全く問題なかったのですが、

import UIKit
import SwiftUI

などのiOSのUI frameworkが動かない問題が発生し、そのエラーを解消するための方法の記事になります

従って、最初からstep by stepで説明するわけではないので、初期設定を済ませていない方は下記の記事など参考に準備してください🙏

導入がまだの場合はこちらなどを参考に:Vim(NeoVim)でSwift -プラグイン, LSPの導入まで

具体的な方法

とりあえず結論

※注意!!!!M1だとx86_64アーキテクチャで動かない場合があり、arm64に変更が必要かもです

swift build -c release -Xswiftc -sdk -Xswiftc /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -Xswiftc -target -Xswiftc x86_64-apple-ios15.2-simulator

参考記事

UIKitに依存するSwift PackageをVSCodeで開発する

iOS Development on VSCode

How to use SourceKit-lsp with iOS projects

no such module ‘UIKit’

Flutter cameraで枠ありのUIを実装する方法

Flutterでカメラ画面で特定の枠を切り抜いているようなUIの実装で少し時間をとってしまったので、記事にしておいてみました

Stackで重ねる方法など色々チャレンジしたのですが、最終的にclipするという方法に落ち着いたので、おそらくほとんどのケースで通用するのでは?と思ってます🙌

※cameraの導入やcontroller変数定義などは公式ドキュメントに従ってご自身で実装してからこちらの記事の内容を検証してください

// widget部分
SizedBox(
  width: double.infinity,
  height: MediaQuery.of(context).size.height * 0.4,
  child: Stack(
    alignment: Alignment.center,
    children: [
      CustomPaint(
        foregroundPainter: Paint(),
        child: SizedBox(
          width: double.infinity,
          child: CameraPreview(controller.value!),
        ),
      ),
      ClipPath(
        clipper: Clip(),
        child: SizedBox(
          width: double.infinity,
          child: CameraPreview(controller.value!),
        ),
      ),
    ],
  ),
)

// CustomerPaint/ClipPathの引数に当てるclass
class Paint extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawColor(Colors.grey.withOpacity(0.7), BlendMode.dstOut);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

class Clip extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    const horizontalPadding = 40.0;
    const verticalPadding = 180.0;
    final path = Path()
      ..addRRect(
        RRect.fromRectAndRadius(
          Rect.fromLTWH(
            horizontalPadding / 2,
            size.height - (size.height - (verticalPadding / 2)),
            size.width - horizontalPadding,
            size.height - verticalPadding,
          ),
          const Radius.circular(10),
        ),
      );
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

参考記事

Add Rectangle overlay in a camera application and Crop the portrait image in flutter

Active InteractionをMPAでハンドリングする方法

普段はAPI開発で利用しているので、Active recordのerrorsに入れるというよりもMapやList形式でエラーを返しているのですが、createが失敗した時のnewをレンダリングする際にちょこっとはまったので記事にしました

まずは最終的なコード

# interaction
module Resources
  module InvoiceInformations
    class Create < ActiveInteraction::Base
      hash :params do
        string :name
        string :zip
        string :prefecture
        string :city
        string :street
        string :building, default: nil
        string :memo, default: nil
      end

      object :current_user, class: User
      validates :current_user, presence: true

      def execute
        invoice_information = current_user.build_invoice_information(params)
        invoice_information.save!
      rescue ActiveRecord::RecordInvalid => e
        # ここ
        e.record.errors.errors.each do |error|
          errors.add(error.attribute, error.message)
        end
        # 公式では下記になってる
        # errors.merge!(e.record.errors.errors)
      end
    end
  end
end

# controller
def create
    outcome = Resources::InvoiceInformations::Create.run(
      params: params_create,
      current_user: current_user
    )
    if outcome.valid?
      @invoice_information = outcome.result
      redirect_to customers_path,
                  notice: t('action_messages.created', model_name: InvoiceInformation.model_name.human)
    else
      @invoice_information = current_user.build_invoice_information(outcome.params)
      # 正直もっと良い方法ありそうだけど、時間の関係上こちらで
      outcome.errors.errors.each do |e|
        @invoice_information.errors.add(e.attribute, e.message)
      end
      render :new
    end
  end

問題点

attributeにbaseが入れられてしまう、が問題です

errors.merge!(e.record.errors.errors) でも当然エラーを返すことができるのですが、errors.merge!に公式の通りのコードを入れると、エラーの対象が特定のカラムではなく全てbaseで表現されてしまいます

煩雑になってしまいますが、丁寧に一つずつエラーをaddすることで目的の挙動を実現できます

※rescue内部でデバッグ実行してclassを確認

公式のコード

<ActiveModel::Error attribute=base, type=blank, options={}>

上記のコードの場合

<ActiveModel::Error attribute=zip, type=blank, options={}>

まとめ

Active Interactionを利用することでusecase的な実装を行うことができるようになり、コードは増えますがより変更に耐えうる実装ができたかと思います

正直Railsを利用するのは否定的ですが、usecaseとして切り出せるのであればまだまだ可能性を感じるので、もうちょい研究とかしていきたいです

Rails + WebpackerでERROR in chunk application [entry] js/[name]-[contenthash].jsが発生

Railsの各種packageのバージョンアップを行なっていたところタイトルのエラーが発生しました

とりあえず結論

config/webpack/development.js を下記のように修正することでエラーを回避できます

process.env.NODE_ENV = process.env.NODE_ENV || 'development'

const environment = require('./environment')

const config = environment.toWebpackConfig();
config.output.filename = 'js/[name]-[hash].js'

module.exports = config;

参考記事

ERROR in chunk application [entry] js/[name]-[contenthash].js Cannot use [chunkhash] or [contenthash] for chunk in .

RiverpodでAsyncValueをawaitする方法

Riverpodを用いて特定のfunction発火の際にawaitする方法でかなり詰まってしまったので、記事に残してます

とりあえずこちらが結論

Future<void> onClicked() async {
  final hoge = await ref.read(hogeProvider.future);
}

whenやwhenData等も検討しましたが、awaitしていないのでタイミング合わず調べていたところこちらの記事を発見しました

AsyncValue data function callback never executed when used from onPressed #628


This is not how AsyncValue works.
when does not “listen” to data/loading/error. It’s a switch-case on the current state.

AsyncValue data function callback never executed when used from onPressed #628

M1でAndroid emulatorを起動させる

M1でAndroid emulator起動させようとしたら下記のエラーが発生しました

% ~/Library/Android/sdk/tools/emulator -list-avds
Pixel_3_API_30
Pixel_4_API_Tiramisu

% ~/Library/Android/sdk/tools/emulator -avd Pixel_4_API_Tiramisu
Could not launch '/Users/masahirookubo/Library/Android/sdk/emulator/qemu/darwin-x86_64/qemu-system-aarch64': No such file or directory

厳密に言うとエラーではなく、該当のファイル or ディレクトリがありません、の問題です

調べて見たところ、こちらの現象は参照しているディレクトリが異なるようで、シンボリックリンクを貼ることで問題解決ができるようです

こちらが該当のシンボリックリンクで、問題のディレクトリまでいきそこで実行することで起動が可能な状態になります

% cd Library/Android/sdk/emulator/qemu
% ln -s darwin-aarch64 darwin-x86_64

上記対応完了後に冒頭のコマンドを実行すると

%  ~/Library/Android/sdk/tools/emulator -avd Pixel_4_API_Tiramisu

emulatorが起動します!

毎回上記コマンドを打ち込むのも面倒なので、私はaliasでこちらを設定することでandroidコマンドだけで起動できるようにしておきました🙌

# .zshrc
alias android="~/Library/Android/sdk/tools/emulator -avd Pixel_4_API_Tiramisu"

参考記事

Run AVD Emulator without Android Studio

How can I launch Android Emulator without android studio on Mac M1

IntelliJ/Android Studioでvimを使う方法

普段NeoVimで開発を行なっているのですが、スマホアプリを開発するにあたってemulatorや解析等々のツールを使った方が良いと思い、Android Studioでもvimが使えるようにしてみました

プラグイン追加

まずはvimを使えるようにするためにプラグインを追加します

IntelliJ/Android Studio -> preferences -> pluginsでIdeaVimを追加

追加した後は再起動必須なので、再起動します

再起動するとvimでの操作が可能になっています

vim機能の有効化

調べてみたところ、IntelliJやAndroid Studioでvimのプラグインを入れても .ideavimrc というファイルが参照されるだけで、自動的に .vimrc が参照されるわけではないみたいです

なので、既存のvim設定を反映させるために .ideavimrc の中身を下記のように変更します

まずはファイルに移動してファイル編集モードへ

vi ~/.ideavimrc

開くことができたらこちらを貼り付けます

source ~/.vimrc

上記のコードを貼り付けることで、 .vimrc に定義しているvimの設定をimportすることが可能になり、intelliJやAndroid Studioでもいつも通りなvim操作を行うことができるようになります

余談

上記の設定で一応vim操作を行うことができるようになるのですが、あくまでもvimの操作だけが可能になります

もしかしたら参照先をnvimに切り替えたらいけるかも?とも思いましたが結果変わらずで、

# .ideavimrc
source ~/.config/nvim/init.vim

plugin等の設定は一切引き継がれないので、その辺りの注意は必要で、確認したところ下記のpluginだけ利用できるみたいです

  • vim-easymotion
  • NERDTree
  • vim-surround
  • vim-multiple-cursors
  • argtextobj.vim
  • vim-textobj-entire
  • ReplaceWithRegister
  • vim-exchange
  • vim-highlightedyank
  • vim-paragraph-motion
  • vim-indent-object
  • match.it

利用可能なpluginsの参考url: https://github.com/JetBrains/ideavim/wiki/Emulated-plugins

個人的には普段利用しているpluginを全て引き継ぎたかったので、最低限の確認はIntelliJ/Android Studioで行い、それ以外の一切の操作は引き続きvimを利用することにしました

とても便利、とうい領域には程遠いですが、マウス操作が減るので最終的には割と効率的な感じにはいけました!

参考記事

Is there a way to get IdeaVIM to honor the mappings from my .vimrc file?

RailsでPostgreSQLをdump importした後にduplicate key value violates unique constraintが出る

RailsのプロジェクトでStagingのDBをdevelopmentに入れたところタイトルのエラーが発生しました

解決策

こちらが解決するためのコード

$ rails c

ActiveRecord::Base.connection.tables.each do |table_name| 
  ActiveRecord::Base.connection.reset_pk_sequence!(table_name)
end

上記実行することで、特定のtableだけではなく全てのtableに対してprimary keyリセットを実行することが可能になります

そもそもの問題点

エラー文に書いてある通り、key valueがダブっています、が問題です

duplicate key value

PostgreSQLでは連番となる数値はシーケンスと呼ばれる、データベースのオブジェクトで、transactionやcommit/rollback関係なくインクリメントされます

通常は勝手にインクリメントされるわけですが、db dump等でimportを行うと、新しいデータベースにschemaをコピーし、シーケンスを1から始めるようです

※importする際は空っぽの新しいデータベースに入れることになるので、sequenceは1から始まる

The Sequence ‘issue’ that in the new database, is probably because the GUI tool used to copy Data over, is simply copying the Schema over to the new Database (which resets the Sequence state). This causes the new Database Sequence to start counting from 1 (instead of what it currently is, in the Old database)

https://stackoverflow.com/questions/32043431/sequence-issue-while-importing-db

参考記事

why PG::UniqueViolation: ERROR: duplicate key value violates unique constraint?

新人にPostgreSQLのシーケンスを理解してもらう