これは何よりも面白いと思います。私はそれを修正しましたが、原因について疑問に思っています。エラーは次のとおりです:DataManager.Swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
。なぜ文句を言うのですか?可能な限り最も単純な表現の1つのようです。
コンパイラはcolumns + ");";
セクションを指します
func tableName() -> String { return("users"); }
func createTableStatement(schema: [String]) -> String {
var schema = schema;
schema.append("id string");
schema.append("created integer");
schema.append("updated integer");
schema.append("model blob");
var columns: String = ",".join(schema);
var statement = "create table if not exists " + self.tableName() + "(" + columns + ");";
return(statement);
}
修正は次のとおりです。
var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";
これも(@efischencyを介して)動作しますが、(
が失われると思うので、あまり好きではありません。
var statement = "create table if not exists \(self.tableName()) (\(columns))"
私はコンパイラの専門家ではありません-この答えが「あなたの考え方を有意義な方法で変える」かどうかはわかりませんが、問題に対する私の理解は次のとおりです。
型推論に関係しています。 +
演算子を使用するたびに、Swiftは+
のすべての可能なオーバーロードを検索し、使用している+
のバージョンを推測する必要があります。 +
演算子のオーバーロードは30未満です。これには多くの可能性があります。4つまたは5つの+
操作をチェーンして、コンパイラーにすべての引数を推測するように依頼すると、一見しただけでなく、それ以上のことが求められます。
この推論は複雑になる可能性があります-たとえば、UInt8
とInt
を+
を使用して追加すると、出力はInt
になりますが、演算子と型を混合するためのルールを評価する作業がいくつかあります。
また、例のString
リテラルのようなリテラルを使用している場合、コンパイラはString
リテラルをString
に変換する作業を行い、その後+
演算子の引数と戻り値の型を推測する作業を行います。
式が十分に複雑な場合、つまり、コンパイラが引数と演算子について多くの推論を行う必要がある場合、式は終了し、終了したことを通知します。
式が特定のレベルの複雑さに達すると、コンパイラを終了させるのは意図的です。別の方法は、コンパイラーにそれを試行させ、実行できるかどうかを確認することですが、それは危険です-コンパイラーは永遠に試行を続け、行き詰まり、または単にクラッシュする可能性があります。したがって、コンパイラの範囲を超えない式の複雑さには静的なしきい値があるというのが私の理解です。
私の理解では、Swiftチームは、これらのエラーをより一般的にしないコンパイラの最適化に取り組んでいます。 このリンクをクリックすると、Apple開発者フォーラムでそれについて少し学ぶことができます 。
開発者フォーラムでは、クリスラトナーは、これらのエラーをレーダーレポートとして提出するように人々に依頼しました。
こことDevフォーラムでいくつかの投稿を読んだ後、それは私が理解する方法ですが、コンパイラの私の理解は素朴であり、これらのタスクをどのように処理するかについてより深い知識を持つ誰かが私が拡張することを望んでいますここに書いています。
これは受け入れられた回答とほぼ同じですが、いくつかの対話(Rob Napier、彼の他の回答、Cocoaheadミートアップからの別の友人との会話)が追加されました。
this ディスカッションのコメントを参照してください。その要点は次のとおりです。
+
operator は27個の異なる関数を持っているので、非常にオーバーロードされているため、4つの文字列を連結する場合、つまり3つの+
演算子がある場合、コンパイラはcheck毎回27人のオペレーター間で、27 ^ 3回です。しかし、それは違います。
また、+
関数のlhs
とrhs
が両方とも有効であるかどうかを確認するために check があります。 append
を呼び出します。そこには、いくつかのやや集中的な checks が発生することがあります。文字列が非連続的に格納されている場合、扱っている文字列が実際にNSStringにブリッジされている場合に該当するようです。 Swiftはすべてのバイト配列バッファーを単一の連続したバッファーに再構成する必要があり、途中で新しいバッファーを作成する必要があります。そして、最終的に、連結しようとしている文字列を含む1つのバッファを取得します。
一言で言えば、3つのクラスターのコンパイラーチェックがあり、これにより速度が低下します。つまり、各サブ式は、すべての観点から再検討する必要がありますmightreturn。その結果、文字列を補間と連結する、つまり" My fullName is \(firstName) \(LastName)"
を使用することは、補間にはオーバーロードがないため、"My firstName is" + firstName + LastName
よりもはるかに優れています
Swift 3はsomeの改善を行いました。詳細については、 コンパイラの速度を落とさずに複数の配列をマージする方法 を参照してください。
SOに関するRob Napierによる他の同様の回答:
私は同様の問題がありました:
expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
Xcode 9.3の行は次のようになります。
let media = entities.filter { (entity) -> Bool in
次のように変更した後:
let media = entities.filter { (entity: Entity) -> Bool in
すべてがうまくいきました。
おそらく、それはSwiftコンパイラが周りのコードからデータ型を推測しようとしていることと関係があるのでしょう。