Ruby on rails iOS核心数据:设置Rails多态关联关系的方法

Ruby on rails iOS核心数据:设置Rails多态关联关系的方法,ruby-on-rails,ios,core-data,Ruby On Rails,Ios,Core Data,我有一个iOS应用程序,其核心数据模型模仿我的Rails后端数据模型。在我的Rails后端模型中,我对一些实体使用多态关联。我的Rails模型如下所示: Airport < ActiveRecord::Base has_many :reviews, :as => :reviewable Restaurant < ActiveRecord::Base has_many :reviews, :as => :reviewable Review < ActiveReco

我有一个iOS应用程序,其核心数据模型模仿我的Rails后端数据模型。在我的Rails后端模型中,我对一些实体使用多态关联。我的Rails模型如下所示:

Airport < ActiveRecord::Base
has_many :reviews, :as => :reviewable

Restaurant < ActiveRecord::Base
has_many :reviews, :as => :reviewable

Review < ActiveRecord::Base
belongs_to :reviewable, :polymorphic => :true
我的问题与核心数据中的MyReview类有关。根据reviewableId和reviewableType中的值设置适当核心数据关系(例如机场或餐厅)的最佳方法是什么

我试过以下方法,但由于种种原因,这些方法看起来都有点不干净。一般来说,在设置正确的关联之前,我需要确保我拥有reviewableId和reviewableType,这似乎是与感知清洁度相关的主要问题。当从JSON中水合这些模型对象时,我并不真正控制在新MyReview对象上填充reviewableId和reviewableType的顺序

1) 一个或两个reviewableId和reviewableType上的自定义setter-在我可以在MyReview模型对象上设置airport或restaurant关系之前,我在每个setter方法中检查另一个属性的值以确保它已填充。一般来说,这是可行的,但感觉不太对,同时在每个setter中都有一些难看的重复代码

- (void)setReviewableId:(NSNumber*)reviewableId {
    [self willChangeValueForKey:@"reviewableId"];
    [self setPrimitiveReviewableId:reviewableId];
    [self didChangeValueForKey:@"reviewableId"];

    if (reviewableId && [reviewableId intValue] != 0 && self.reviewableType) {
        if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

            MyAirport myAirport = <... lookup MyAirport by airportId = reviewableId ...>
            if (myAirport) {
                self.airport = myAirport;
            }

        } else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

            MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = reviewableId ...>
            if (myRestaurant) {
                self.restaurant = myRestaurant;
            }
        }
    }
}

- (void)setReviewableType:(NSString*)reviewableType {
    [self willChangeValueForKey:@"reviewableType"];
    [self setPrimitiveReviewableType:reviewableType];
    [self didChangeValueForKey:@"reviewableType"];

    if (self.reviewableId && [self.reviewableId intValue] != 0 && reviewableType) {
        if (self.airport == nil && [reviewableType isEqualToString:@"Airport"]) {

            MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
            if (myAirport) {
                self.airport = myAirport;
            }

        } else if (self.restaurant == nil && [reviewableType isEqualToString:@"Restaurant"]) {

            MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
            if (myRestaurant) {
                self.restaurant = myRestaurant;
            }
        }
    }
}
-(void)setReviewableId:(NSNumber*)reviewableId{
[self Will ChangeValueForkey:@“reviewableId”];
[self-setPrimitiveReviewableId:reviewableId];
[self-didChangeValueForKey:@“reviewableId”];
if(reviewableId&&[reviewableId intValue]!=0&&self.reviewableType){
如果(self.airport==nil&&[self.reviewableType IsequalString:@“airport”]){
我的机场我的机场=
如果(我的机场){
self.airport=myAirport;
}
}else if(self.restaurant==nil&&[self.reviewableType IsequalString:@“restaurant”]){
我的餐厅我的餐厅=
如果(我的餐厅){
self.restaurant=myRestaurant;
}
}
}
}
-(void)setReviewableType:(NSString*)reviewableType{
[self Will ChangeValueForkey:@“reviewableType”];
[self-setPrimitiveReviewableType:reviewableType];
[self-didChangeValueForKey:@“reviewableType”];
if(self.reviewableId&&[self.reviewableId intValue]!=0&&reviewableType){
如果(self.airport==nil&&[reviewableType IsequalString:@“airport”]){
我的机场我的机场=
如果(我的机场){
self.airport=myAirport;
}
}else if(self.restaurant==nil&&[reviewableType IsequalString:@“restaurant”]){
我的餐厅我的餐厅=
如果(我的餐厅){
self.restaurant=myRestaurant;
}
}
}
}
2) 在awakeFromInsert和awakeFromFetch中,我注册模型对象以通过KVO观察它自己的reviewableId和reviewableType属性。让对象观察自己感觉很难看,但至少我有一个方法来处理填充关联,这似乎比#1有点改进。请注意,我确实在这里使用dealloc方法中的removeObserver:forKeyPath:导致了一些崩溃(例如,崩溃表示我删除了一个不存在的观察者??),因此这远不是经过验证的代码

- (void)awakeFromFetch {
    [super awakeFromFetch];
    [self addObserver:self forKeyPath:@"reviewableId" options:0 context:nil];
    [self addObserver:self forKeyPath:@"reviewableType" options:0 context:nil];
}

- (void)awakeFromInsert {
    [super awakeFromInsert];
    [self addObserver:self forKeyPath:@"reviewableId" options:0 context:nil];
    [self addObserver:self forKeyPath:@"reviewableType" options:0 context:nil];
}

- (void)dealloc {
    [self removeObserver:self forKeyPath:@"reviewableId"];
    [self removeObserver:self forKeyPath:@"reviewableType"];
    [super dealloc];
}

- (void)updatePolymorphicAssociations {
    if (self.reviewableId && [self.reviewableId intValue] != 0 && self.reviewableType) {
        if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

            MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
            if (myAirport) {
                self.airport = myAirport;
            }

        } else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

            MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
            if (myRestaurant) {
                self.restaurant = myRestaurant;
            }
        }
    }
}

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
    [self updatePolymorphicAssociations];
}
-(void)awakeFromFetch{
[super awakeFromFetch];
[self-addObserver:self-forKeyPath:@“reviewableId”选项:0上下文:nil];
[self-addObserver:self-forKeyPath:@“reviewableType”选项:0上下文:nil];
}
-(无效)从插入中唤醒{
[super awakeFromInsert];
[self-addObserver:self-forKeyPath:@“reviewableId”选项:0上下文:nil];
[self-addObserver:self-forKeyPath:@“reviewableType”选项:0上下文:nil];
}
-(无效)解除锁定{
[self-removeObserver:self-forKeyPath:@“reviewableId”];
[self-removeObserver:self-forKeyPath:@“reviewableType”];
[super dealoc];
}
-(void)updatePolymorphicAssociations{
if(self.reviewableId&&[self.reviewableId intValue]!=0&&self.reviewableType){
如果(self.airport==nil&&[self.reviewableType IsequalString:@“airport”]){
我的机场我的机场=
如果(我的机场){
self.airport=myAirport;
}
}else if(self.restaurant==nil&&[self.reviewableType IsequalString:@“restaurant”]){
我的餐厅我的餐厅=
如果(我的餐厅){
self.restaurant=myRestaurant;
}
}
}
}
-(void)observeValueForKeyPath:(NSString*)对象的键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文{
[自更新多态关联];
}
3) 使用上面的updatePolymorphicAssociations方法重写willSave。这似乎是可行的,但它会推迟对关联的所有更改,直到我们去保存对象,而在我们对reviewableId和reviewableType进行初始更改时,通常不会保存对象。在这里,通过后台线程插入一堆新的MyReview对象似乎也有一些限制,可能与willSave有关,实际上导致我们刚刚保存的对象发生更改,从而再次触发willSave。即使使用nil签入updatePolymorphicAssociations,我似乎仍然能够使用这种方法使应用程序崩溃

- (void)updatePolymorphicAssociations {
    if (self.reviewableId && [self.reviewableId intValue] != 0 && self.reviewableType) {
        if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

            MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
            if (myAirport) {
                self.airport = myAirport;
            }

        } else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

            MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
            if (myRestaurant) {
                self.restaurant = myRestaurant;
            }
        }
    }
}

- (void)willSave {
    [self updatePolymorphicAssociations];
}
-(void)updatePolymorphicAssociations{
if(self.reviewableId&&[self.reviewableId intValue]!=0&&self.reviewableType){
如果(self.airport==nil&&[self.reviewableType IsequalString:@“airport”]){
我的机场我的机场=
如果(我的机场){
self.airport=myAirport;
}
}else if(self.restaurant==nil&&[self.reviewableType IsequalString:@“restaurant”]){
我的餐厅我的餐厅=
如果(我的餐厅){
- (void)updatePolymorphicAssociations {
    if (self.reviewableId && [self.reviewableId intValue] != 0 && self.reviewableType) {
        if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

            MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
            if (myAirport) {
                self.airport = myAirport;
            }

        } else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

            MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
            if (myRestaurant) {
                self.restaurant = myRestaurant;
            }
        }
    }
}

- (void)willSave {
    [self updatePolymorphicAssociations];
}
Review{
        //... some review attributes
    place<<-(required)->ReviewablePlace.reviews //... logically a review must always have a place that is reviewed
}

ReviewablePlace(abstract){ 
    reviewableID:Number //... in case you have to fetch on this ID number later
    reviews<-->>Review.place
}

Airport:Reviewable{
    //... some airport specific attributes
}

Restaurant:Reviewable{
    //... some restaurant specific attributes
}
if Airport
  fetch on reviewableID
    if fetch returns existing Airport managed object 
      break //don't want a duplicate so don't create an object
    else 
      create new Airport managed object with reviewableID
      break
if Restaurant
  fetch on reviewableID
    if fetch returns existing Restaurant managed object 
      break //don't want a duplicate so don't create an object
    else 
      create new Restaurant managed object with reviewableID
      break
if Review
  fetch on reviewableID
  if fetch returns Reviewable object of either subclass
    create new Review object and assign fetched Reviewable object to the Review.place relationship
    break
  else
    create new Airport or Resturant object using the JSON provided reviewableID and reviewableType info
    create new Review object and assign the newly created Reviewable subclass object to the Review.place relationship
    break