MacOS Cocoaアプリ作成法初心者向け Objective-C XIBファイルでラジオボタン制御を行う

XCodeのバージョンは13.0 2012年の頃開発したmacosアプリが全くコンパイル通らなくなり長期戦で改修を行うため基本からやり直しのためまずラジオボタンの切り替え処理を考えてみました。これが正攻法かどうかわかりませんが一つの方法ではあります
もっと簡単な方法があるなどありましたらご意見お願いします。
以前はラジオボタンはNSMatrixというクラスがあったのですがなくなりそれの対応方法でもあります
# cocoaアプリケーションサンプルを生成
:::note
Xcodeでの部品とイベントの結びつけ方
NSMatrixがなくなりラジオボタン処理のやり方をテスト
:::
New Project macosを選択しNext
XIB と Objecective-Cを選択する
![スクリーンショット 2021-11-07 9.21.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/d9bd0871-37ce-58a9-2c58-8d582d4cf363.png)

プロジェクト名は任意
Product Name: に任意の名前をつけて生成します

![MsinMenuSel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/28ba8e81-bc2d-1aa4-e652-6cc8e53578a2.png)
次にMainMenu.xibファイルを選択するとウインドウが表示されます
 (macosApp1のタイトルが見えます)
![MainWindowxib.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/752e8b76-0ba8-a9d6-3d49-b1330a0f1ce7.png)

画面のオブジェクトクラスを追加します
* File ->新規で cocoaクラスの追加をします(mファイルとhファイルを追加します)
![NewClassAdd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/32430314-7d6c-9acf-a172-b2a599ffc2ba.png)
* AppWindowという名前のクラス名にします(任意で良い）
* mファイルとhファイルが追加されました
![classadded.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/4b663053-b218-89fc-ad69-5d3059ea2c00.png)
オブジェクト（ウインドウ専用の）を左側のバーに追加します
* XIBファイルをアクティブにしたままシフト＋コマンドキー＋Lでライブラリ追加画面を出します
* Objectを選択したまま左側のバーにドラッグドロップするとついかされて青線の立方体が追加されます
![AddFromLibray.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/da0bad5b-fa48-ef41-f93a-65593a4f8e50.png)
立方体(最初にプロジェクト作成時に既に存在していたもの、NSObjectなど)が３つになったのを確認しますー最下のBOXが今回手動で追加したObjectになります
![objectto3box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/a56dbc17-d8bf-59c2-1d30-71df367fa27a.png)
選択したObjectを選択してClass名をソースファイル(m,h)のクラス名と同じように入力します
![ClassDefine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/fd11718e-d1d1-1eb0-bc57-aae126a905a1.png)
選択した立方体のオブジェクト名がAppWindowに設定されました

![ObjectaddEnd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/d0714321-d5a6-c24d-5e69-091008f94f04.png)
------------------------------------

 ラジオボタンを３つ追加します。Titleは別にします
![radiobuttonadd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/ba28e839-2f2f-dac3-5686-ca45220bbe55.png)
radioボタンのプロパティを変更する画面
Identifierに数字を入れます。３つのラジオボタンすべて行います
![identify_input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/4ae92c2d-401d-0d73-32ac-1f7c42582764.png)

##ボタン切り替えイベントと関数の紐付け
１、まずアシスタントView(メニューのEditor>Assistant)を右側に表示させておきますがソースコード画面と同じ感じ
　しかしactionのドラッグ＆ドロップが出来ます
　私の場合はこの便利な方法はYouTubeで見て知りました
対応するソースコードは先ほど追加した立方体と同じ名前のクラスのヘッダーファイルを表示しておいてからドラッグを開始します

![xcode-assistant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/b96b325f-dcb9-5be6-f317-8603220afc7f.png)
２、ラジオボタンを右マウスクリックしてactionからドラッグして関数を追加します
 この操作を３つのラジオボタンすべてに行うことでどのラジオボタンを押して切り替えても同じイベント処理関数が呼ばれます
一つの関数内でどのラジオボタンが押されたかを判定して処理を記載した方が効率的かと思いますが、ラジオボタンの切り替え処理をソースコードに記述することでも可能です。つまりラジオボタンが押されたらそのラジオボタン固有の関数が呼ばれる、そして他ラジオボタンが選択されていたら解除して押されたラジオボタンを選択状態(setState NSControlStateValueOn)とする
その場合はどのラジオボタンかを判定することは必要なくなるかと思います

![action-addFunction.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200517/a98ccaad-1146-4d95-3d03-f0aead94dd81.png)


```AppWindow.h
//
//  AppWindow.h
//  macosApp1
//
//  Created by macuser1 on 2021/11/14.
//

#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

@interface AppWindow : NSWindow {
    IBOutlet NSTextField* mLabel;
    __weak IBOutlet NSButton *mRdoEast;
    __weak IBOutlet NSButton *mRdoWest;
}
- (id)initWithCorder:(id)sender;
- (IBAction)OnRadioSel:(id)sender;
- (IBAction)OnRadioEast:(id)sender;
- (IBAction)OnRdioWest:(id)sender;

@end

NS_ASSUME_NONNULL_END

```

関数をxibファイルに結びつける作業をやるとXcodeでの関数の先頭は丸いマークが付きます
関数定義の中身(任意)を下記に示します
３つのラジオボタンはidentifierを独自に定義して１つのイベント関数に３つのボタンを結びつけることで自動でラジオボタンの選択が切り替わります
右側の２つのラジオボタンは定義をそれぞれのaction関数に紐付けているため自動的には切り替わらないのでトグルになるようにソースコードで対象ラジオボタンの選択を解除させています


``` AppWindow.m

//
//  AppWindow.m
//  macosApp1
//
//  Created by macuser1 on 2021/11/14.
//

#import "AppWindow.h"

@implementation AppWindow

- (id)initWithCorder:(id)sender {
    
    self = [super init];
    
    mLabel = [NSTextField new];
    
    return self;
}
- (IBAction)OnRadioSel:(id)sender {
    NSLog(@"OnRadioSel %@", sender);
    NSButton* pmtx = sender;
    //NSLog(@"Pushed In ¥n");
    NSString* sel = [[pmtx selectedCell] identifier];
    NSLog(@"Pushed %@ Button", sel);
    [mLabel setStringValue: [NSString stringWithFormat: @"Select %@", sel]];
}
- (IBAction)OnRadioEast:(id)sender
{
    NSLog(@"OnRadioEast %@", sender);
    NSButton* pmtx = sender;
    //NSLog(@"Pushed In ¥n");
    NSString* sel = [[pmtx selectedCell] identifier];
    NSLog(@"OnPushEast %@ Button", sel);
    [mLabel setStringValue: [NSString stringWithFormat: @"Select %@", sel]];

    [mRdoWest setState:NSControlStateValueOff];
}
- (IBAction)OnRdioWest:(id)sender {
    NSLog(@"OnRadioWest %@", sender);
    NSButton* pmtx = sender;
    //NSLog(@"Pushed In ¥n");
    NSString* sel = [[pmtx selectedCell] identifier];
    NSLog(@"OnPushWest %@ Button", sel);
    [mLabel setStringValue: [NSString stringWithFormat: @"Select %@", sel]];
    
    [mRdoEast setState:NSControlStateValueOff];
}
@end
```

mRdoEast、mRdoWestの２つの部品コントロールはinit時にインスタンスをソースコードで生成していません。これはアシスタントでヘッダーに追加したせいかそのまま使用出来ています
ヘッダーでweak,strongの識別子がついていますがこれはassistantで追加する際にせってい出来ます。メモリ管理上の対応で通常はweakで良いです