代码之家  ›  专栏  ›  技术社区  ›  Dan Ray

无法从nsmutableset添加或删除对象

  •  0
  • Dan Ray  · 技术社区  · 14 年前

    检查一下:

    - (IBAction)toggleFavorite {
        DataManager *data = [DataManager sharedDataManager];
        NSMutableSet *favorites = data.favorites;
    
        if (thisEvent.isFavorite == YES) {
            NSLog(@"Toggling off");
            thisEvent.isFavorite = NO;
            [favorites removeObject:thisEvent.guid];
            [favoriteIcon setImage:[UIImage imageNamed:@"notFavorite.png"] forState:UIControlStateNormal];
        }
        else {
            NSLog(@"Toggling on, adding %@", thisEvent.guid);
            thisEvent.isFavorite = YES;
            [favorites addObject:thisEvent.guid];
            [favoriteIcon setImage:[UIImage imageNamed:@"isFavorite.png"] forState:UIControlStateNormal];
        }
        NSLog(@"favorites array now contains %d members", [favorites count]);
    }
    

    这是从自定义ui按钮激发的。ui部分工作得很好——切换按钮使用的图像,我可以从其他东西看到thisevent.isFavoriteBool正在愉快地切换。我还可以在调试器中看到我正在获取数据管理器singleton。

    但这是我的nslog:

    2010-05-13 08:24:32.946 MyApp[924:207] Toggling on, adding 05db685f65e2
    2010-05-13 08:24:32.947 MyApp[924:207] favorites array now contains 0 members
    2010-05-13 08:24:33.666 MyApp[924:207] Toggling off
    2010-05-13 08:24:33.666 MyApp[924:207] favorites array now contains 0 members
    2010-05-13 08:24:34.060 MyApp[924:207] Toggling on, adding 05db685f65e2
    2010-05-13 08:24:34.061 MyApp[924:207] favorites array now contains 0 members
    2010-05-13 08:24:34.296 MyApp[924:207] Toggling off
    2010-05-13 08:24:34.297 MyApp[924:207] favorites array now contains 0 members
    

    最糟糕的是,这曾经奏效,我不知道我做了什么来打破它。

    --编辑:根据请求,我的共享数据单件代码:

    h

    #import <Foundation/Foundation.h>
    
    @interface DataManager : NSObject {
        NSMutableArray *eventList;
        NSMutableSet *favorites;
    }
    
    @property (nonatomic, retain) NSMutableArray *eventList;
    @property (nonatomic, retain) NSMutableSet *favorites;
    
    +(DataManager*)sharedDataManager;
    
    @end
    

    M:

    #import "DataManager.h"
    
    static DataManager *singletonDataManager = nil;
    
    @implementation DataManager
    
    @synthesize eventList;
    @synthesize favorites;
    
    +(DataManager*)sharedDataManager {
        @synchronized(self) {
            if (!singletonDataManager) {
                singletonDataManager = [[DataManager alloc] init];
            }
        }
        return singletonDataManager;
    }
    
    - (DataManager*)init {
        if (self = [super init]) {
            eventList = [[NSMutableArray alloc] init];
            favorites = [[NSMutableSet alloc] init];
        }
        return self;
    }
    

    ------编辑编辑编辑------

    在@techzen的建议下,我将访问方法移到了数据管理器singleton中。现在的情况如下:

    #import "DataManager.h"
    
    static DataManager *singletonDataManager = nil;
    
    @implementation DataManager
    
    @synthesize eventList;
    @synthesize favorites;
    
    +(DataManager*)sharedDataManager {
        @synchronized(self) {
            if (!singletonDataManager) {
                singletonDataManager = [[DataManager alloc] init];
            }
        }
        return singletonDataManager;
    }
    
    - (DataManager*)init {
        if (self = [super init]) {
            eventList = [[NSMutableArray alloc] init];
            favorites = [[NSMutableSet alloc] init];
        }
        return self;
    }
    
    
    #pragma mark -
    #pragma mark Data management functions
    
    - (void)addToFavorites:(NSString *)guid
    {
        [self.favorites addObject:guid];
        NSLog(@"Item added--we now have %d faves.", [favorites count]);
    }
    
    - (void)removeFromFavorites:(NSString *)guid
    {
        [favorites removeObject:guid];
        NSLog(!"Item removed--we now have %d faves.", [self.favorites count]);
    }
    
    
    @end
    

    我让我的视图控制器在发生这种情况的地方调用 [[DataManager sharedManager] addToFavorites:Event.guid] 我没有将项目直接添加到收藏夹集本身,而是将日志记录的内容留在了原来的位置。

    这是我的日志:

    2010-05-13 13:25:52.396 EverWondr[8895:207] Toggling on, adding 05db685f65e2
    2010-05-13 13:25:52.397 EverWondr[8895:207] Item added--we now have 0 faves.
    2010-05-13 13:25:52.398 EverWondr[8895:207] favorites array now contains 0 members
    2010-05-13 13:25:53.578 EverWondr[8895:207] Toggling off
    2010-05-13 13:25:53.579 EverWondr[8895:207] favorites array now contains 0 members
    

    所以…DataManager对象甚至不能向其自身属性添加任何内容!它不会像不可变类型那样抛出异常,它只是无声地失败了!

    只是为了好玩,我把它改成了一个我更熟悉的非可变数组。相同的行为。

    1 回复  |  直到 14 年前
        1
  •  4
  •   TechZen    14 年前

    正如上面的Phellicks建议的,您可能不会返回可变集 data.favorites . 不过,如果是这样的话,您应该得到一个编译器警告。

    这个 05db685f65e2 不是真正的guid。它看起来更像一个对象的地址。您应该检查“thisevent.guid”上的类型,以确保您得到了一个对象和正确的对象类型。

    与你的主要问题无关,我想补充一下(1)这一点:

    NSMutableSet *favorites = data.favorites;
    

    …是毫无意义的,只是添加了另一个可能的错误源。没有理由不使用 数据收藏夹 直接在代码中。(见下文(3))

    (2)在访问外部对象(甚至是单例对象)时,最好将对外部对象的引用作为类的属性,尤其是在数据模型等关键对象的情况下。这允许您控制和跟踪对外部对象的访问。

    (3)不要将单例变量视为裸全局变量。这会导致悲伤。相反,用特定的方法包装对数据模型内部数据的访问。例如,而不是访问 数据收藏夹 直接创建如下方法:

    - (void) addToFavoritesGuid:(id) aGuid;
    

    - (void) addToFavoritesGuid:(GuidClass *) aGuid;
    

    这将使您的数据模型能够控制其内部,并使其能够拒绝添加不应属于内部的对象。

    编辑

    从评论:

    好吧,这就是我的本来面目 返回。。。我只是用调试 通过我的单件初始化器。 检查我的数据管理器的IVARS 对象,我看到我的收藏,其中 在初始化时用收藏夹初始化 =[[nsmutableset alloc]init];实际上是作为nscfset创建的, 我不知道那是什么,也不知道那是什么 制造它…

    与所有集合和字符串一样,nsset实际上是一个类集群,即所有共享相同接口的子类的集合。当你创建一个集合时,你得到的实际类可能会有所不同,这取决于它是如何创建的。在这种情况下,您将返回NSore核心基础集,这是NSSET的标准核心类。

    因此,你的问题是 favorites 初始化为可变集,但被分配给不可变集。这就是为什么你不能添加任何内容。

    此初始化:

    favorites = [[NSMutableSet alloc] init];
    

    …正在由以下人员处置:

    nsmutableset*favorites=data.favorites;
    

    如果您有一个实例变量,并且您创建了一个同名的局部变量,那么局部符号将在创建它的范围内占主导地位。这似乎有效,因为作为nsset的子类,nsmutableset响应nsset的所有方法和属性。

    但是,在构建时,您必须从链接器中收到大量警告。你不应该忽视那些错误。您应该将它们视为致命错误,因为它们在运行时就是这样。

    要解决您的问题:

    (1)将data.favorites声明为可变数组,然后直接访问它。将另一个局部变量赋给同一个地址不会给您带来任何好处。

    (2)将Favorites声明为当前对象的可变数组属性。从初始化 数据收藏夹 像: self.favorites=[nsmutableset setwithcapacity:[data.favorites count]]; [self.favorites集:data.favorites]; /…添加或删除项目 data.favorites=self.favorites;

    (3)将在data.favorites中添加或删除对象的所有逻辑移动到数据模型对象中的自定义方法(请参见上文)

    三是最好的选择。

    编辑02

    看起来类集群隐藏了集群中所有类的真实类。我运行了以下测试代码:

    - (void)applicationDidFinishLaunching:(UIApplication *)application {    
        NSSet *s=[NSSet setWithObject:@"setWithObject"];
        NSMutableSet *m=[NSMutableSet setWithCapacity:1];
        [m addObject:@"Added String"];
        NSMutableSet *n = [[NSMutableSet alloc] initWithCapacity:1];
        [self showSuperClasses:s];
        [self showSuperClasses:m];
        [self showSuperClasses:n];
        [self showSuperClasses:@"Steve"];   
    }
    
    - (void) showSuperClasses:(id) anObject{
        Class cl = [anObject class];
        NSString *classDescription = [cl description];
        while ([cl superclass]) 
        {
            cl = [cl superclass];
            classDescription = [classDescription stringByAppendingFormat:@":%@", [cl description]];
        }
        NSLog(@"%@ classes=%@",[anObject class], classDescription);
    }
    

    …得到这个输出:

     NSCFSet classes=NSCFSet:NSMutableSet:NSSet:NSObject
     NSCFSet classes=NSCFSet:NSMutableSet:NSSet:NSObject
     NSCFSet classes=NSCFSet:NSMutableSet:NSSet:NSObject
     NSCFString classes=NSCFString:NSMutableString:NSString:NSObject
    

    很明显,来自调试器和类函数的报告对于找出属于集群的任何实例的真实类都是无用的。以前不是这样的。这是最近的变化。我认为这是核心基金“免费桥接”的一部分。

    您可以将项添加到Favorites,因为这两个类中的Favorites的所有定义都是不可变的。

    在任何情况下,您的问题是在同一个类中有两个独立的收藏夹定义。链接器警告您说:

    Local declaration of "favorites" hides instance variable

    我认为这个问题可以通过运行时混淆这两个最爱来解释。将对象添加到一个收藏夹,但记录另一个。

    本地对收藏的重新定义毫无意义。 移除它并查看问题是否仍然存在。