PC パソコン

Swift「Invalid redeclaration」の原因と解決方法

Swiftで同じ名前のVariable、Property、Function、Type、Enum Caseなどを重複して定義すると、Xcodeに次のようなErrorが表示されることがあります。

Invalid redeclaration of 'name'

例えば:

Invalid redeclaration of 'ContentView'

や:

Invalid redeclaration of 'viewDidLoad()'

などです。

このErrorは、同じScopeや同じModule内で、Compilerから見て区別できないDeclarationが複数存在している場合に発生します。

代表的な原因は、同じClassやStructを2回定義した、同名Propertyを重複して書いた、同じSignatureのFunctionを複数作った、Extensionと本体で同じMemberを定義した、FileをCopyした際に古いSourceがTargetへ残っている、Generated Codeと手書きCodeが衝突している、といったものです。

解決するときは、Errorが表示された行だけを見るのではなく、同じ名前・同じSignatureのDeclarationがProject内のどこに重複しているかを検索し、どちらを残すべきか判断することが重要です。

  1. 「Invalid redeclaration」とは
  2. なぜ同名Functionを作れる場合と作れない場合があるのか
  3. 代表的な発生状況
  4. 主な原因
    1. 1. 同じVariableを同一Scopeで2回宣言している
    2. 2. Class内で同じPropertyを2回宣言している
    3. 3. Struct内で同じPropertyを重複している
    4. 4. 同じFunction Signatureを複数定義している
    5. 5. Return Typeだけを変えてOverloadしようとしている
    6. 6. 同じClassを別Fileで定義している
    7. 7. SwiftUIのContentViewを複数作った
    8. 8. Extensionで同じPropertyやMethodを定義している
    9. 9. 複数Extensionで同じMethodを定義している
    10. 10. Global Functionを複数Fileへ定義している
    11. 11. Enum Caseを重複している
    12. 12. TypealiasとType名が衝突している
    13. 13. Protocol名と別Type名が衝突している
    14. 14. Nested Typeを重複している
    15. 15. IBOutlet Propertyを重複して追加した
    16. 16. IBAction Methodを重複している
    17. 17. File Copy後に同じDeclarationが残っている
    18. 18. Generated Codeと手書きCodeが衝突している
    19. 19. Core DataのCodegen設定と手書きClassが重複している
    20. 20. Merge Conflict解消時に同じCodeを2回残した
  5. まず確認すること
    1. 1. Error Messageに表示された名前をProject全体で検索する
    2. 2. 同じFile内だけでなくProject全体を見る
    3. 3. FunctionならSignature全体を比較する
  6. 解決方法1:重複Declarationを削除する
  7. 解決方法2:別の意味を持つ値なら名前を変更する
  8. 解決方法3:Function Nameを変更する
  9. 解決方法4:正しくOverloadする
  10. 解決方法5:Argument Labelを変えて区別する
  11. 解決方法6:同名Typeの片方をRenameする
  12. 解決方法7:CopyしたFileのClass Nameを変更する
  13. 解決方法8:不要なCopy FileをTargetから外す
  14. 解決方法9:Backup FileはProject外へ移動する
  15. 解決方法10:Extension内の重複Methodを削除する
  16. 解決方法11:本体とExtensionの責務を分ける
  17. 解決方法12:SwiftUIのContentView重複を解消する
  18. 解決方法13:Preview用Viewと本番ViewのNameを分ける
  19. 解決方法14:Enum Caseの重複を削除する
  20. 解決方法15:TypealiasのNameを変更する
  21. 解決方法16:ProtocolとConcrete TypeのNameを分ける
  22. 解決方法17:IBActionやIBOutletの重複を削除する
  23. 解決方法18:Core DataのCodegen設定を確認する
  24. 解決方法19:Generated Sourceを確認する
  25. 解決方法20:同じGenerated Fileを2回Compileしていないか確認する
  26. 解決方法21:Compile Sourcesの重複や不要Fileを確認する
  27. 解決方法22:Target Membershipを確認する
  28. 解決方法23:同じModule内のGlobal Declarationを検索する
  29. 解決方法24:Nested TypeのNameを変更する
  30. 解決方法25:Merge Conflict後の重複Codeを確認する
  31. 解決方法26:OverloadのSignatureを意図的に区別する
  32. 解決方法27:Argument LabelでAPIの意味を分ける
  33. 解決方法28:同名PropertyをComputed PropertyとStored Propertyで重複させない
  34. 解決方法29:同名MethodとPropertyの衝突を確認する
  35. 解決方法30:XcodeのProject SearchでDeclarationを絞り込む
  36. SwiftUIで「Invalid redeclaration」が出る場合
  37. ClassやStructで発生する場合
  38. Functionで発生する場合
  39. Extensionで発生する場合
  40. Core Dataで発生する場合
  41. 「Project内に1つしかないはず」なのに出る場合
  42. Clean Build Folderで直るか
  43. DerivedData削除は必要か
  44. やってはいけない対処
  45. 最短で確認するチェックリスト
  46. まとめ

「Invalid redeclaration」とは

redeclarationは「再宣言」という意味です。

例えば:

let title = "Hello" let title = "World"

同じScopeでtitleを2回DeclarationしているためErrorになります。

同様に:

struct User { }

struct User {
}

のように同じType名を重複して定義しても:

Invalid redeclaration of 'User'

となります。

なぜ同名Functionを作れる場合と作れない場合があるのか

SwiftはFunction Overloadをサポートしています。

例えば:

func show(value: String) { }

func show(value: Int) {
}

はParameter Typeが異なるため別Functionとして区別できます。

一方:

func show(value: String) { }

func show(value: String) {
}

は完全に同じSignatureなので区別できずInvalid redeclarationになります。

ポイント:名前が同じでもCompilerがSignatureで区別できればOverloadとして成立します。区別できないDeclarationを重複させるとInvalid redeclarationになります。

代表的な発生状況

  • 同じVariableを2回定義した
  • 同じPropertyをClassやStruct内へ2回書いた
  • 同じFunction Signatureを複数定義した
  • 同じClassやStructを別Fileでも定義した
  • 同じEnumを重複定義した
  • 同じEnum Caseを重複させた
  • Extensionと本体で同じMemberを定義した
  • 同じProtocol Extensionを重複させた
  • SwiftUIのContentViewを複数Fileで定義した
  • FileをCopyした後、元FileとCopy Fileの両方がTargetに含まれている
  • 旧Source Fileを削除したつもりでもTarget Membershipに残っている
  • Generated Codeと手書きCodeが同じTypeやPropertyを生成している
  • Core DataのClass Generationと手書きNSManagedObject Subclassが衝突している
  • 同じIBActionやIBOutlet Propertyを重複して定義した
  • 同じGlobal Functionを複数Fileへ書いた

主な原因

1. 同じVariableを同一Scopeで2回宣言している

let count = 10 let count = 20

同じScopeでは同名Variableを再Declarationできません。

2. Class内で同じPropertyを2回宣言している

final class UserViewModel { var name = "" var name = "" }

nameが重複しています。

3. Struct内で同じPropertyを重複している

struct User { let id: Int let id: Int }

4. 同じFunction Signatureを複数定義している

func save(name: String) { }

func save(name: String) {
}

Function Name、Argument Label、Parameter Typeなどから区別できません。

5. Return Typeだけを変えてOverloadしようとしている

例えば:

func load() -> String { "Hello" }

func load() -> Int {
10
}

Call SiteのContextによって区別できる場面もありますが、API Designとして曖昧になりやすく、同じDeclarationとして問題になる構成があります。

ParameterやFunction Nameなど、Call Siteから明確に区別できる設計にする方が安全です。

6. 同じClassを別Fileで定義している

例えば:

// User.swift final class User { }

別Fileにも:

// UserCopy.swift final class User { }

があると、同じModule内では重複します。

7. SwiftUIのContentViewを複数作った

Project Templateの:

struct ContentView: View { var body: some View { Text("Hello") } }

を残したまま、別Fileへ同名ContentViewを作るとErrorになります。

8. Extensionで同じPropertyやMethodを定義している

struct User { func displayName() -> String { "User" } }

extension User {
func displayName() -> String {
"User"
}
}

9. 複数Extensionで同じMethodを定義している

extension User { func reset() { } }

extension User {
func reset() {
}
}

10. Global Functionを複数Fileへ定義している

同一Module内のTop-level Declarationは別Fileにあっても衝突することがあります。

11. Enum Caseを重複している

enum Status { case active case inactive case active }

12. TypealiasとType名が衝突している

struct User { }

typealias User = String

同じScopeで同名Typeとして扱えない構成になります。

13. Protocol名と別Type名が衝突している

protocol Downloadable { }

struct Downloadable {
}

同一Scope内でType Nameが衝突します。

14. Nested Typeを重複している

struct Container { struct Item { }
struct Item {
}

}

15. IBOutlet Propertyを重複して追加した

@IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var titleLabel: UILabel!

16. IBAction Methodを重複している

@IBAction func didTapButton(_ sender: UIButton) { }

@IBAction func didTapButton(_ sender: UIButton) {
}

17. File Copy後に同じDeclarationが残っている

ViewController.swiftをCopyして名前だけFile側で変更し、内部のClass Nameを変更し忘れるケースです。

// HomeViewController.swift final class HomeViewController: UIViewController { }

// HomeViewControllerCopy.swift
final class HomeViewController: UIViewController {
}

18. Generated Codeと手書きCodeが衝突している

Code GeneratorやBuild Toolが生成したTypeを、自分でも同じ名前で定義している場合があります。

19. Core DataのCodegen設定と手書きClassが重複している

Core Data EntityでClass Definitionなどの自動生成を有効にしたまま、同じNSManagedObject Subclassを手書きするとDuplicate Typeが発生する場合があります。

20. Merge Conflict解消時に同じCodeを2回残した

Git Merge後に、似たDeclarationを両方残してしまうケースがあります。

まず確認すること

1. Error Messageに表示された名前をProject全体で検索する

例えば:

Invalid redeclaration of 'User'

なら、XcodeのProject Searchで:

User

を検索します。

より絞り込むなら:

struct User class User enum User typealias User

などを探します。

2. 同じFile内だけでなくProject全体を見る

Declarationは別Fileに存在していても同じModuleなら衝突する場合があります。

重要:Errorが出たFile内に重複が見つからない場合、別File、Extension、Generated Source、Target Membershipを確認してください。

3. FunctionならSignature全体を比較する

例えば:

func update( name: String, age: Int )

と同一のFunctionが別の場所にないか確認します。

解決方法1:重複Declarationを削除する

最も基本的な修正です。

問題:

let title = "Hello" let title = "World"

修正:

let title = "Hello"

不要な方を削除します。

解決方法2:別の意味を持つ値なら名前を変更する

let pageTitle = "Hello" let buttonTitle = "Continue"

役割が違うなら、意味を表す別名にします。

解決方法3:Function Nameを変更する

同じSignatureで処理内容が異なるなら:

func saveUser( name: String ) { }

func cacheUser(
name: String
) {
}

のように意図が分かるNameへ変更します。

解決方法4:正しくOverloadする

同じFunction Nameを使いたい場合は、Compilerが区別できるSignatureにします。

func show( value: String ) { }

func show(
value: Int
) {
}

Parameter Typeが異なるためOverloadとして利用できます。

解決方法5:Argument Labelを変えて区別する

func load( id: Int ) { }

func load(
index: Int
) {
}

Call Siteが:

load(id: 10) load(index: 10)

のように区別できる設計ならOverloadとして成立する場合があります。

解決方法6:同名Typeの片方をRenameする

例えば:

struct User { }

と:

struct APIUser { }

のように、Domain ModelとAPI Modelを別Nameにします。

解決方法7:CopyしたFileのClass Nameを変更する

FileをDuplicateした場合、File Nameだけでなく内部のType Nameも変更してください。

final class SettingsViewController: UIViewController { }

のように、新しい役割に合わせたNameへ変更します。

解決方法8:不要なCopy FileをTargetから外す

同じSourceを一時BackupとしてProjectへ置いている場合、そのFileがApp Targetへ含まれているとCompile対象になります。

XcodeのFile Inspectorで:

Target Membership

を確認し、Build対象に不要なFileなら対象Targetから外します。

解決方法9:Backup FileはProject外へ移動する

例えば:

ContentView_old.swift ContentView_copy.swift ViewController_backup.swift

のようなBackup SourceをProjectへ追加したままにすると、内部Declarationが同じ場合に衝突します。

Version Controlを利用し、不要なSource CopyはCompile対象から除外する方が安全です。

解決方法10:Extension内の重複Methodを削除する

問題:

extension User { func reset() { } }

extension User {
func reset() {
}
}

どちらか一方だけを残します。

解決方法11:本体とExtensionの責務を分ける

例えば、本体:

struct User { let name: String }

Extension:

extension User { var displayName: String { name.uppercased() } }

のようにMemberが重複しないよう整理します。

解決方法12:SwiftUIのContentView重複を解消する

Project全体から:

struct ContentView: View

を検索します。

複数見つかったら、不要な方を削除するか:

struct SettingsView: View { var body: some View { Text("Settings") } }

のように別Nameへ変更します。

解決方法13:Preview用Viewと本番ViewのNameを分ける

Preview検証用に別Viewを作る場合:

struct ContentViewPreviewSample: View { var body: some View { ContentView() } }

など、既存Typeと衝突しないNameを使用します。

解決方法14:Enum Caseの重複を削除する

問題:

enum Status { case active case inactive case active }

修正:

enum Status { case active case inactive }

解決方法15:TypealiasのNameを変更する

Type Nameと衝突している場合:

struct User { }

typealias UserName = String

のように別Nameへ変更します。

解決方法16:ProtocolとConcrete TypeのNameを分ける

例えば:

protocol Downloading { func download() }

final class Downloader:
Downloading {
func download() {
}
}

のように役割が分かるNameにします。

解決方法17:IBActionやIBOutletの重複を削除する

StoryboardからControl-dragを繰り返した結果、同じPropertyやMethodを複製していないか確認します。

@IBOutlet weak var titleLabel: UILabel!

は通常1つだけで十分です。

解決方法18:Core DataのCodegen設定を確認する

Core Data Entityで自動Class生成を使っている場合、同じEntity用のNSManagedObject Subclassを手書きすると重複することがあります。

Data Model InspectorでEntityの:

Codegen

設定を確認してください。

自動生成を利用するのか、Manual/Noneで手書きClassを管理するのかを統一します。

注意:Core Data関連の生成方式はProject構成によって異なります。自動生成と手動生成を同じEntityで重ねないことが重要です。

解決方法19:Generated Sourceを確認する

Code Generation Tool、Swift Macro、Build Pluginなどが同じType名やMember名を生成していないか確認します。

自分で書いていないDeclarationが原因の場合は、Build LogやGenerated Sourcesを確認してください。

解決方法20:同じGenerated Fileを2回Compileしていないか確認する

Generated Fileが複数のBuild PhaseやSource Directoryから重複して取り込まれると、同じDeclarationが2回Compileされる構成になる場合があります。

XcodeのTarget設定で:

Build Phases → Compile Sources

を確認します。

解決方法21:Compile Sourcesの重複や不要Fileを確認する

同じSource FileのCopyや古いFileがCompile Sourcesへ残っていないか確認します。

ただし、通常Xcodeが同一File Referenceを単純に二重登録する問題よりも、内容が同じ別Fileが含まれているケースの方が多いため、File Nameだけでなく中身も確認してください。

解決方法22:Target Membershipを確認する

同じTypeを持つFileを複数Targetで使うこと自体は問題にならない場合がありますが、同じTarget・Module内に重複Declarationが入るとErrorになります。

File Inspectorで、どのTargetに含まれているか確認してください。

解決方法23:同じModule内のGlobal Declarationを検索する

Global Function:

func logMessage( _ message: String ) { }

が複数Fileに存在していないかProject Searchで確認します。

解決方法24:Nested TypeのNameを変更する

struct Response { struct Item { }
struct Metadata {
}

}

同じContainer内のNested Type名を一意にします。

解決方法25:Merge Conflict後の重複Codeを確認する

Git MergeやCherry-pick後に、同じMethodが離れた場所へ2回残っていないか確認してください。

例えば:

func configureUI() { ... }

をProject Searchして、同じType内に複数ないか確認します。

解決方法26:OverloadのSignatureを意図的に区別する

例えばStringとURLで処理を分けたいなら:

func load( value: String ) { }

func load(
value: URL
) {
}

のようにConcrete Typeを変えます。

解決方法27:Argument LabelでAPIの意味を分ける

func load( id: Int ) { }

func load(
index: Int
) {
}

Call Siteで意味を明確に区別できるため、単なるDuplicate Declarationより読みやすいAPIになります。

解決方法28:同名PropertyをComputed PropertyとStored Propertyで重複させない

問題:

struct User { var name = "Alice"
var name: String {
    "Bob"
}

}

Stored PropertyとComputed Propertyでも同じNameを共有できません。

例えば:

struct User { var name = "Alice"
var displayName: String {
    name.uppercased()
}

}

のように役割ごとにNameを分けます。

解決方法29:同名MethodとPropertyの衝突を確認する

同じMember Nameを異なる種類のDeclarationで使うと衝突する場合があります。

APIとして分かりやすい別名へ変更してください。

解決方法30:XcodeのProject SearchでDeclarationを絞り込む

例えばErrorが:

Invalid redeclaration of 'reset'

なら:

func reset

や:

var reset

をProject Searchすると原因を見つけやすくなります。

SwiftUIで「Invalid redeclaration」が出る場合

SwiftUIではViewをFile単位で増やすことが多いため、同じType Nameを作ってしまうケースがあります。

特に確認するもの:

  1. ContentViewが複数ないか
  2. Custom ViewをCopyした後にStruct Nameを変更したか
  3. Preview用のTest Viewと本番Viewが同名でないか
  4. Extensionで同じComputed Propertyを追加していないか
  5. 同じViewModelを複数Fileで定義していないか

ClassやStructで発生する場合

例えば:

final class SettingsViewModel { var title = "" var title = "" }

なら、同名Propertyの片方を削除するかRenameします。

別Fileにも同じSettingsViewModelがないかProject全体で確認してください。

Functionで発生する場合

問題:

func calculate( value: Int ) -> Int { value * 2 }

func calculate(
value: Int
) -> Int {
value * 3
}

処理内容が異なってもSignatureが同じなので区別できません。

例えば:

func doubled( value: Int ) -> Int { value * 2 }

func tripled(
value: Int
) -> Int {
value * 3
}

のようにNameを変えます。

Extensionで発生する場合

Type本体とExtensionを両方検索します。

struct User { func formattedName() -> String { "User" } }

extension User {
func formattedName() -> String {
"User"
}
}

同じMemberは一方だけにします。

Core Dataで発生する場合

NSManagedObject Subclassを手動生成した後にEntityのCodegenがClass Definitionのままだと、同じClassが自動生成され、手書きClassと衝突する場合があります。

確認する流れ:

  1. .xcdatamodeldを開く
  2. 対象Entityを選択する
  3. Data Model Inspectorを開く
  4. ClassとModuleを確認する
  5. Codegen設定を確認する
  6. 自動生成か手動管理かを統一する

「Project内に1つしかないはず」なのに出る場合

次を確認してください。

  • 同じDeclarationを持つCopy File
  • Target Membership
  • Extension
  • Generated Source
  • Core Data Codegen
  • Swift MacroやBuild Pluginの生成物
  • 別Folderにある古いSource
  • Merge後に残ったDuplicate Code
  • Compile Sourcesへ含まれているFile

Clean Build Folderで直るか

通常、Source Code上に本当に重複Declarationがある場合はClean Build Folderでは直りません。

補助的に:

Product → Clean Build Folder

を試すことはできますが、同じTypeやMemberが2つ定義されていればCode修正が必要です。

DerivedData削除は必要か

IndexやGenerated Artifactの古い状態が疑われる場合には、補助的なTroubleshootingとしてDerivedDataを削除することがあります。

rm -rf ~/Library/Developer/Xcode/DerivedData/*

ただし、これはProject内のDuplicate Declarationを削除する操作ではありません。

注意:まずProject Searchで同名Declaration、Target Membership、Generated Codeを確認してください。Cache削除は最後の補助策です。

やってはいけない対処

Errorを消すためだけに、意味のないSuffixを付けて片方を残す方法は避けてください。

例えば:

func save2() { }

のように適当にRenameすると、APIの役割が分かりにくくなります。

本当に同じ機能ならDuplicateを削除し、別の機能なら役割を表すNameへ変更してください。

また、重複しているFileをFinderから削除する前に、そのFileが必要なSourceではないか、Version Controlで復元可能かも確認してください。

最短で確認するチェックリスト

  1. Errorに表示された名前をProject全体で検索する
  2. 同じFile内に重複Declarationがないか確認する
  3. 別Fileに同名Class・Struct・Enumがないか確認する
  4. FunctionならSignature全体を比較する
  5. Extensionで同じMemberを定義していないか確認する
  6. Copy FileやBackup Fileを確認する
  7. Target Membershipを確認する
  8. Build PhasesのCompile Sourcesを確認する
  9. SwiftUIのContentViewなど同名Viewを確認する
  10. Enum Caseの重複を確認する
  11. TypealiasとType Nameの衝突を確認する
  12. IBOutlet・IBActionの重複を確認する
  13. Generated Sourceを確認する
  14. Core DataのCodegenを確認する
  15. Merge後のDuplicate Codeを確認する

まとめ

Swiftの「Invalid redeclaration」は、Compilerから見て同じ名前・同じSignatureとして扱われるDeclarationが重複している場合に発生します。

代表的な原因は、同名Variable・Property・Function・Class・Struct・Enumの重複、Extension内のDuplicate Member、Copy File、SwiftUIの同名View、Generated Code、Core Data Codegenなどです。

最初にError Messageへ表示されたNameをXcodeのProject Searchで検索し、同じDeclarationがどこに存在するか確認してください。

本当に重複しているだけなら不要なDeclarationを削除し、別の役割を持つものなら意味が分かるNameへ変更します。

Functionを同名で使いたい場合は、Parameter TypeやArgument Labelなど、Compilerが明確に区別できるSignatureへ変更してOverloadとして設計します。

Project内に重複が見つからない場合は、Target Membership、Extension、Generated Sources、Core DataのCodegen、Build Phasesも確認してください。

Clean Build FolderやDerivedData削除は補助的な対処にすぎず、Source Code上のDuplicate Declarationそのものは修正できません。