[SwiftUI / MacOS]既存メニューバー項目を取り除く

# 結論から
![スクリーンショット 2021-11-07 15.38.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245014/faf22aaf-8328-bf53-4a80-b45d0b796a0e.png)
MacOSのアプリケーションを作成するときにデフォルトで提供されているメニューバーを取り除きたくなる時があると思います．StoryBoardを利用する場合はサクッとできますがSwiftUIの機能だけではサクッとできません．そのため，StoryBoard時代の機能を経由してメニューバーからデフォルトの項目を取り除きます．

```swift:sampleApp.swift
import SwiftUI

@main
struct palmShortcutApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate  // ①
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

// ②
class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {
        let rmMenuTitles = Set(["File", "Edit", "View", "Window", "Help"])
        
        if let mainMenu = NSApp.mainMenu {
            let menus = mainMenu.items.filter { item in
                return rmMenuTitles.contains(item.title)
            }
            for i in menus {
                mainMenu.removeItem(i)
            }
        }
    }
}
```

# 説明
上のコードをコピペするだけでOKですが，簡単に説明を書きます．

## ① SwiftUI時代のAppDelegate
ここでStoryBoard時代のAppDelegateを接続します．プロジェクトを作成する際にSwiftUIを選択した場合はAppDelegateがありませんので，自分たちで作成する必要があります．ただし，SwiftUIではファイルを作成する必要がありません．そのため，今回のようなメニューバーから特定の項目を削除するみたいな少ないコードは`[App名].swift`の中に直接classを定義しても何ら問題はありません．

## ② class定義
ここがAppDelegateの本体になります．やっていることは単純です．
1. 既存のメニューバーのタイトルを（手入力ですが）集合型で定義
2. メニューバーの項目名をループし，項目名が集合に含まれていればメニューバーから削除する

ここで注意したいのが，このコードは英語版（つまりデフォルト）のメニューしか削除できないということです．レアケースだとは思いますが，プロジェクトを日本語化している人は最初の集合型の定義を日本語に書き直す必要があります．もちろん他の言語圏も同様です．

# おまけ（メニューの追加）
既存のメニューを削除しましたが，オリジナルなメニューを追加したいこともあると思います．
その場合はSwiftUIの`.commands`を利用すると良いです．

```swift:sampleApp.swift
import SwiftUI

@main
struct palmShortcutApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .commands { // 追加
            CommandMenu("sample"){
                SampleCommand()
            }
        }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {
        let rmMenuTitles = Set(["File", "Edit", "View", "Window", "Help"])
        
        if let mainMenu = NSApp.mainMenu {
            let menus = mainMenu.items.filter { item in
                return rmMenuTitles.contains(item.title)
            }
            for i in menus {
                mainMenu.removeItem(i)
            }
        }
    }
}

// 追加
struct SampleCommand: View {
    var body: some View {
        Button("print Hello"){
            print("Hello")
        }
    }
}
```

すると以下のように既存のメニューが削除され，オリジナルのメニューだけになります．
![スクリーンショット 2021-11-07 15.35.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245014/058b98c2-60b3-7e14-8b99-5d5aad52f14c.png)

ご参考になれば幸いです．

# 参考
SwiftUIでは「既存メニュー項目に新しいメニューを追加すること」が簡単にできるようになっていますので，一般的なアプリケーションを作成する場合は`.CommandGroup(replacing: .after)`とかを有効活用すると良さそうです．

https://software.small-desk.com/development/2021/09/20/swiftui-macos-howto-commands/

https://software.small-desk.com/development/2021/10/10/swiftui-howto-macosmenu-modification/