masalibの日記

システム開発、運用と猫の写真ブログです

【StoryBoard】Navigation Controller導入手順

NavbarはXcodeのデフォルトの機能です。GUIで追加することは可能だったのですが初心者の自分には知らない場所にあって苦労したのでそのときのメモです

前提

ViewControllerがある状態です

変更前

ViewControllerを選択した状態で、EditorでEmbed In → Navigation Controllerを選択します

するとNavigation Controllerが追加されます

なぜかデフォルトだと無色らしいので色を変えました
Barを選択する

AppearnaceでStandardとScroll Edgeを選択する

Scroll Edge AppearnaceのBackgroundで色を変更する Scroll Edge Title AttrbutesのTitleをCustomに変更して、Title Colorで色を変更する

変更後

【StoryBoard】TabBarControler導入手順

TabBarControlerはXcodeのデフォルトの機能です。 初心者の自分がすこしハマったことのメモです

環境

Xcode 15.3 Build version 15E204a

TabBarControlerを作る

StoryBoardで「+」を押してその後「Tab」を入力すると

TabBarControlerが表示されるのでそれをドラッグアンドドロップする

デフォルトで2つタブが作られる

TabBarControlerにViewを追加する

StoryBoardで「+」を押してその後「ViewControl」を入力すると

ViewControlerが表示されるのでそれをドラッグアンドドロップする

親のTabBarControlerをcontrolボタンを押しながらクリックして その後、作成したViewControlerをクリックすると ポップアップが表示されるので

Relationship Segue
 view controller
を選択する

タブが追加される (あとはタブのアイコンなどを変えたりすればOK)

順番変更について

タブの順番を変更するには、TabBarControllerの各ViewControllerをドラッグ&ドロップします。 タブバーに関連付けられている各ViewControllerは、Storyboard上でTabBarControllerの下に小さな矢印で接続されています。これらのViewControllerをドラッグして並べ替えることで、アプリ内でのタブの順序を変更できます。

参考URL
https://qiita.com/kapiemon/items/7812f64597244644ca4b

【Swift】PrefixHeader.pch で定義された内容を swift で使う

古いアプリをリプレイするために少し調べています
ベースは Swift で作ってどうしても難しいところは Object-c のソースを呼び出す形にしたいと思っています 私は Xcode の開発に関しては初心者なので調べたことを残しています。

環境について

Xcode 15.3 Build version 15E204a

作業目的

SwiftでもObjective-Cでも同じ定数を使う。デバックログはマクロではできないので違う形になるかと思う

前の記事でPrefixHeader.pchが使えてdefineの定義されているものが使えるようになった

masalib.hatenablog.com

その内容を今度はSwiftで使うようにしたい

前提

Swift は Objective-C とは異なり、プレフィックスヘッダ (PrefixHeader.pch) を直接サポートしていません。プレフィックスヘッダは、特定のヘッダをプロジェクトの全ソースファイルで自動的にインポートする Objective-C の機能でしたが、Swift ではこのような機能は提供されていません。

対応方法

ブリッジングヘッダの使用: Objective-C のコードを Swift ファイルからアクセス可能にするために、Swift ではブリッジングヘッダ ({ProjectName}-Bridging-Header.h) を使用します。Objective-C のヘッダをブリッジングヘッダにインポートすることで、Swift からそれらを利用できるようになります。

ブリッジングヘッダの作成

({ProjectName}-Bridging-Header.hを新規作成して以下のようなプログラムを書きます importは前回つくったDefienファイルになります

//
//  inapppurchasetest-Bridging-Header.h
//  inapppurchasetest
//
//  Created by masalib on 2024/03/16.
//

#ifndef inapppurchasetest_Bridging_Header_h
#define inapppurchasetest_Bridging_Header_h
#import "CommonDefine.h"

#endif /* inapppurchasetest_Bridging_Header_h */

対象 TARGET の Bulid Settings の Objective-C Bridging Header で上記ファイルのパスを指定する。

$(SRCROOT)/$(PROJECT)/$(SWIFT_MODULE_NAME)-Bridging-Header.h

と設定する。

Swiftで使う

ソースでは何も指定することなくDefine.hで指定されている内容が使える

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        print("test")
        print(MAX_HISTORIES)
        // Do any additional setup after loading the view.
    }
}

参考URL

https://qiita.com/ysn/items/fa85612cb5adf9a4c05d

【Objective-C】PrefixHeader.pchを使う

Objective-C初心者のメモです。

環境について

Xcode 15.3 Build version 15E204a

PrefixHeader.pch とは

システムが大きくなると Define という定数をつくります 当たり前ですが class 単位ではなくアプリ全体で使います。 Objective-C だと PrefixHeader.pch というものを使いかならず読み込ませるようにします

作成方法

プロジェクトファイルの直下に「PrefixHeader.pch」を追加する。

新規ファイルを追加して「Filter」に「PCH」を入力すると選択させます

対象 TARGET の Bulid Settings の PrefixHeader で上記ファイルのパスを指定する。

上記「Prefix Header」を押下して

$(SRCROOT)/$(PROJECT)/PrefixHeader.pch

と設定する。

define を設定する。

以下のような define のファイルを作成する

//
//  CommonDefine.h
//
//  Created by Masalib on 2024/03/16.
//  Copyright (c) 2024年 Masalib Inc. All rights reserved.
//

#ifndef CommonDefine_h
#define CommonDefine_h

#define MAX_HISTORIES   100
#define MAX_FAVORITES   50

//-- お問い合わせメアド
#define INQUIRY_MAIL_ADDRESS    @"masalib@gmail.com"


#endif

PrefixHeader.pch を修正する。

作った define ファイルを読み込ませる

//
//  PrefixHeader.pch
//

#ifndef PrefixHeader_pch
#define PrefixHeader_pch

// Include any system framework and library headers here that should be included in all compilation units.
// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.

#import "CommonDefine.h"


#endif /* PrefixHeader_pch */

Objective-C で使う。

NSLog(@"問い合わせアドレスは%@", INQUIRY_MAIL_ADDRESS);

【Swift】CocoaPods導入手順

M1 MacにCocoaPodsをインストールしてXcodeで使う手順をご紹介します。M1チップを搭載したMacでは、いくつかの追加のステップが必要になる場合があります。

開発環境

OS

$ sw_vers

ProductName:     macOS
ProductVersion:     14.2.1
BuildVersion:       23C71

shellについて

Rosettaはインストールされている
shellはRosettaを使っている前提です

$ uname -m

x86_64

Xcode

$ xcodebuild -version

Xcode 15.3
Build version 15E204a

Cocoapods

$ pod -version

1.4.3

CocoaPodsのインストール

  1. ターミナルを開く

    Finderから「アプリケーション」>「ユーティリティ」>「ターミナル」を選択するか、Spotlight検索で「ターミナル」と入力して開きます。

  2. Homebrewのインストール (まだの場合)

    M1 MacにCocoaPodsをインストールする前に、Homebrew(パッケージマネージャー)がインストールされている必要があります。以下のコマンドでHomebrewをインストールできます。

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

    Homebrewのインストール後、以下のコマンドを実行して、ターミナルでHomebrewコマンドを使用できるようにします。

     echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
     eval "$(/opt/homebrew/bin/brew shellenv)"
    
  3. CocoaPodsのインストール

    Homebrewを使用してCocoaPodsをインストールします。ターミナルで以下のコマンドを実行してください。

     brew install cocoapods
    

CocoaPodsの使用

  1. Podfileの作成

    Xcodeプロジェクトのディレクトリに移動します。ターミナルで以下のコマンドを使用して、プロジェクトのルートディレクトリに移動します(「YourProjectName」は実際のプロジェクト名に置き換えてください)。

     cd /path/to/YourProjectName
    

    プロジェクトのルートディレクトリで以下のコマンドを実行し、Podfileを作成します。

     pod init
    
  2. Podfileの編集

    Podfileを開き、必要なライブラリを指定します。Podfileはプロジェクトのルートディレクトリにあります。テキストエディタで開いて編集します。例えば、FirebaseAnalyticsをプロジェクトに追加する場合は、Podfileに以下のように記述します。

platform :ios, '14.0'
# 共通
def install_pods
  pod 'Firebase/Analytics', '8.15.0'
end

target 'inapppurchasetest' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for inapppurchasetest
  install_pods
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = "14.0"
    end
  end
end
  1. ライブラリのインストール

    Podfileに必要なライブラリを記述したら、ターミナルで以下のコマンドを実行して、それらのライブラリをプロジェクトにインストールします。

     pod install
    

    このコマンドを実行すると、CocoaPodsが依存関係を解決し、指定されたライブラリをインストールします。プロセスが完了すると、 .xcworkspaceファイルが作成されます。

  2. Xcodeでの作業

    ライブラリをインストールした後、「.xcodeprojファイル」ではなく、生成された「.xcworkspaceファイル」を開いて、Xcodeで作業を続けてください

この作業ででたエラー

Sandbox: rsync.samba(24373) deny(1) file-write-create /Users/masalib/Library/Developer/Xcode/DerivedData/inapppurchasetest-gcmthumwhaymfgcrpylvjcjoqbax/Build/Products/Debug-iphoneos/inapppurchasetest.app/Frameworks/ASValueTrackingSlider.framework/.ASValueTrackingSlider.eoX9S4

このエラーメッセージは、Sandboxがrsyncプロセスが指定されたパスにファイルを作成することを拒否したことを示しています。具体的には、XcodeのDerivedData内にあるinapppurchasetestプロジェクトのビルドプロセス中に、ASValueTrackingSlider.frameworkに関連する一時ファイルの作成が許可されていない状況です。

色々調べてみたら

appdev-room.com

というのがでた

解決方法はXcodeの「Build Settings」>「User Script Sandboxing」の値をNoにすることでエラーが解消することができました。

ここの値はXcode14まではデフォルトがNOでしたがXcode15からYESに切り替わったようです 初心者でこのエラーは辛いよ

参考URL https://qiita.com/s11y/items/3090290cb72434852460

javascriptで日付セレクトボックスを作る

自分用のメモです 下記のサイトを参考にしてつくった

qiita.com

日付セレクトボックスに初期値を設定するためには、 Counter関数を呼び出した後で、特定の年月日を選択状態にする処理を追加する必要があります。初期値を設定するには、option要素のselected属性をtrueに設定します。

以下のステップで初期値を設定する方法を示します。

  • showYearCounter関数に初期値を設定するための引数を追加します(例:defaultYear, defaultMonth, defaultDay)。
  • Counter関数に初期値を渡して、その値に対応するoption要素を選択状態にします。
  • Counter関数内で、渡された初期値(もしあれば)に基づいて、該当するoptionのselected属性をtrueに設定します。
<!DOCTYPE html>
<html>

<head>
    <title>日付選択</title>
    <script>
        // 数値カウンターまとめ
        function Counter(elementId, start, end, defaultValue) {
            const element = document.getElementById(elementId);
            element.innerHTML = '';
            for (let i = start; i <= end; i++) {
                let option = document.createElement("option");
                option.value = i;
                option.text = i;
                // 初期値が設定されていれば、該当するoptionを選択状態にする
                if (i === defaultValue) {
                    option.selected = true;
                }
                element.appendChild(option);
            }
        }

        // 年月はまとめてカウンターに渡して生成
        function showYearCounter(yearId, monthId, dayId, defaultYear, defaultMonth, defaultDay) {
            Counter(yearId, 1900, 2020, defaultYear);
            Counter(monthId, 1, 12, defaultMonth);
            showdayCounter(yearId, monthId, dayId, defaultDay);
        }

        // 日だけ年月で3パターンを判定してカウンター関数に投げる
        function showdayCounter(yearId, monthId, dayId, defaultDay) {
            let year = document.getElementById(yearId).value;
            let month = document.getElementById(monthId).value;
            let februaryDays = leap(year) ? 29 : 28;

            if (month == 2) {
                Counter(dayId, 1, februaryDays, defaultDay);
            } else if (month.match(/^(4|6|9|11)$/)) {
                Counter(dayId, 1, 30, defaultDay);
            } else {
                Counter(dayId, 1, 31, defaultDay);
            }
        }

        // 閏年判定
        function leap(year) {
            return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
        }

        // ここで初期値を設定して関数を呼び出す
        //showYearCounter('year', 'month', 'day', 2000, 1, 1);
    </script>
</head>

<body>
    <body onload="showYearCounter('year', 'month', 'day', 2000, 1, 1);">
        <select id="year" onchange="showdayCounter('year', 'month', 'day');"></select>年
        <select id="month" onchange="showdayCounter('year', 'month', 'day');"></select>月
        <select id="day"></select>日
    </body>
</html>

選択した内容を保存または表示させる必要がある場合はイベントリスナーを追加する必要がある

document.getElementById('year').addEventListener('change', updateDate);
document.getElementById('month').addEventListener('change', updateDate);
document.getElementById('day').addEventListener('change', updateDate);

function updateDate() {
    const year = document.getElementById('year').value;
    const month = document.getElementById('month').value;
    const day = document.getElementById('day').value;
    
    // 年月日が選択されていない場合は処理をしない
    if (!year || !month || !day) return;

    const formattedDate = `${year}${month}${day}日`;
    console.log(formattedDate); // コンソールに表示
    
    // 必要に応じて保存処理を追加
    // 例:DOMに表示する
    document.getElementById('selectedDate').textContent = formattedDate;
    
    // 例:ローカルストレージに保存
    localStorage.setItem('selectedDate', formattedDate);
}

// 初期日付設定後の変更イベントを発火させる
function initAndUpdateDate() {
    showYearCounter('year', 'month', 'day', 2000, 1, 1); // 初期日付を設定
    updateDate(); // 初期設定時に日付を更新
}

initAndUpdateDate();

WordPressの勉強 vol.1

現在、WordPressの開発というかデザインの修正をおこなっているのですが そもそもWordPressの構造を理解しておらず、現在どのプログラムが実行されているのかわかりませんでした 勉強しているとテンプレート階層と呼ばれる構造になっていることを知りました

http://wpdocs.osdn.jp/wiki/images/wp-template-hierarchy.jpg

実際に実行されているのを確認するには

Query Monitor

というプラグインを入れると 実行されているプログラムがわかるようになりました

早く知りたかった・・・

ちょっとびっくりしたのが SQLのクエリーの回数がわかるみたい

サイトトップだけど

f:id:masalib:20210104194414p:plain

クエリー回数が多いような・・・こんなもの?