2016-09-19 12 views
2

ジェネリックメソッドは、実行中のクラスに基づいて型を推測することは可能ですか? CoreData NSManagedObjectモデルを使用してローカルデータを格納および取得し、すべてのものを読みやすく、使いやすい方法で汎用的にすることができました。これが正しく、データベース内の「すべて」のポストオブジェクトを返しますが、構文がタイプする必要がありSwiftを使用したクラスメソッドの汎用タイプを推論する

let posts: [Post] = Post.all() 

:ユーザーがオブジェクトのリストを取得するためのローカルデータベースを照会したい場合、彼は次の行を記述しますPostクラス(Post.all())からメソッドを呼び出すときに、(不要な冗長性があると判断された)メソッドの上に([Post])を定義する必要があります。 Postクラスからall()メソッドを呼び出すだけでジェネリック型を定義する方法はありますか?私はそうのように、私はちょうどデータをフェッチするグローバル関数を作成することができます想像:

let posts: [Post] = all() 

これは、構文は次のとおりだった場合、それは次のようになりほど読める感じない:

let posts = Post.all() 

ポイントこれを改善しようとすると、このプロジェクトを手に入れる開発者は、構造やスタイルをすばやく学ぶことができます。また、将来の一般的なコードの読みやすさを向上させることができます。

は、より多くの洞察力のために、ここでは現在の構造について、もう少し情報です:

//Model.swift - The model base class. All models extend this class. 

class Model: NSManagedObject { 
    /** 
    Some other stuff here 
    **/ 

    //MARK: Fetch 
    internal class func fetch<T: Model>(predicate: NSPredicate? = nil) -> [T]? { 
     do { 
      if let request = NSFetchRequest.FromEntityName(self.entityName) { //Get entity with the name defined in the current class 
       request.predicate = predicate 
       if let result = try self.context?.executeFetchRequest(request) as? [T] { 
        return result 
       } 
      } 
     } 
     catch let error as NSError { 
      Log.Error("\(error)") 
     } 
     return nil 
    } 

    //MARK: Fetch general 
    class func all<T: Model>() -> [T]? { 
     if let result: [T] = self.fetch() { 
      return result 
     } 
     Log.warning("No \(self.entityName) found") 
     return nil 
    } 
} 

//Post.swift - An example model class. Extends Model.swift 

class Post: Model { 
    //some fields 
} 

//Example view controller 
class ViewController: UIViewController { 
    override func viewDidLoad() { 
     let posts: [Post] = Post.all() 
     //do stuff 
    } 
} 

誰もがその後、私に知らせてくださいについての考えを持っている場合。すべての助けに感謝します!

答えて

5

一般的に、クラスメソッドがサブクラスに対しても「クラスの型」を返す一般的な方法は、プロトコル拡張とSelf型を使用することです。プロトコルの

// define a protocol 
protocol ModelType {} 
// create a static method on the protocol that returns [Self] 
extension ModelType where Self: NSManagedObject { 
    static func all() -> [Self]? { 
     return [Self]() // do your fetch here 
    } 
} 
// conform to the protocol in your class hierarchy 
class Model: NSManagedObject, ModelType {} 
class Post: Model {} 

let posts = Post.all() 
// implicit type of `posts` is `[Post]?` 
all()は、プロトコル拡張によって提供されるべきである。なお

が、ない要件:ここでは型チェックは、あなたが望むように動作させるために最低限まであなたのアプローチを沸騰例です。 。 all()protocol ModelTypeの中に宣言すると、動的なディスパッチを使用することができません。これは、動的なタイプを使用する場合に必要です。

また

、スウィフト3であることに注意(およびMacOSの10.12/iOS搭載10/tvOS 10/watchOS 3)は、コアデータ自体はあなた自身のために定義されてきたものの一部を置き換えるいくつかのスウィフトAPIのショートカットを定義します。 What's New in Core Dataからこの例を注意:スタイルのお好みに

func findAnimals() { 
    context.performAndWait({ 
     let request = Animal.fetchRequest // implicitly NSFetchRequest<Animal> 
     do { 
      let searchResults = try request.execute() 
      // use searchResults ... 
     } catch { 
      print("Error with request: \(error)") 
     } 
    }) 
} 

最後に、いくつかの解説...

はFYI私はちょうど大会

としてすべての静的/クラスメソッドの最初の文字を大文字に

これを改善しようとする点はあるように、これを拾う任意の開発者プロジェクトは多くの労力を費やすことなく、構造とスタイルを素早く学ぶことができますまた、これがうまくいけば、将来的に

を一般的なコードの可読性が向上します私は(Swift 3 API Guidelinesで推奨小文字のメソッド名など)、言語標準の規則から破壊することは、それを作るあなたの目標と非常に互換性があることはよく分かりませんあなたのコードベースを初めて知っている他の開発者が読んで参加するのは簡単です。

+0

私はそれを試してみましょう。また、RE:コードスタイル - 私はそれを検討します。大会そのものは、スウィフトで他の人と仕事をしていたにもかかわらず、それは標準であった。しかし、私はこのプロジェクトでは協力していませんので、言語ガイドラインが違う点を指摘すれば、それを確立する理由はないと思います。 –

+0

私がこれを実装し始めたのを見てきたことの一つは、 'let request = Animal.fetchRequest'は' let request = Animal.fetchRequest() 'でなければなりません。他の人がこの回答を見ると、その修正を使ってあなたの回答を編集するのに役立つかもしれません。 –

関連する問題