Singleton 类 DataLoader - 在 AppDelegate 中从 Core Data 设置值,但无法访问其他类中的 DataLoader 变量

Posted

技术标签:

【中文标题】Singleton 类 DataLoader - 在 AppDelegate 中从 Core Data 设置值,但无法访问其他类中的 DataLoader 变量【英文标题】:Singleton class DataLoader - set values from Core Data in AppDelegate, however cannot access DataLoader variables in other classes 【发布时间】:2012-01-16 22:40:09 【问题描述】:

我一直在绞尽脑汁,进行了很多搜索,但到目前为止还没有运气。

基本上,我已设置 Core Data 以将数据从 AppDelegate 类中的 sqlite db 加载到名为 DataLoader 的单例类中的共享变量中。

我还有一个名为 GameScene 的主类,它也将使用 DataLoader 数据。

我想要做的如下:

从 DB 加载数据(使用后台线程)并将结果存储在 DataLoader 单例类变量中(特别是 NSMutableArray) 以这种方式在场景转换到主菜单区域时加载数据 在 GameScene 类中,我尝试访问存储在 DataLoader 单例中的数据,并在游戏中使用这些数据。

我的问题是,虽然我可以看到我将对象存储在 AppDelegate 类中,但我似乎无法返回 GameScene 类中的对象。通常以 EXC_BAD_ACCESS 错误结束。

我真的在寻找一些类似的例子,或者如果你有任何想法。

如果您需要代码示例,请告诉我。

谢谢, 普拉斯。

*编辑 - 代码片段*

DataLoader.h

#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface DataLoader : NSObject 



//setup singleton
+(DataLoader *) sharedDataLoader;
@property (nonatomic, retain) NSMutableArray * veHint;//2 characters

DataLoader.m

#import "DataLoader.h"
#import <CoreData/CoreData.h>

@implementation DataLoader
@synthesize veHint;

static DataLoader * myDataLoader = nil;

+(DataLoader *) sharedDataLoader

    if(myDataLoader == nil)
        myDataLoader = [[[DataLoader alloc]init]retain];
    
    return myDataLoader;


-(id) init

    if((self = [super init]))
        veHint = [NSMutableArray arrayWithCapacity:10];
    
    return self;

AppDelegate.mm

#import "AppDelegate.h"
#import "GameScene.h"
#import "RootViewController.h"
#import "Word.h"
#import "DataLoader.h"
-(void) applicationDidFinishLaunching:(UIApplication*)application

//other standard stuff here...

//my load data method using data loader
[self getRandomData];

//other standard stuff here...

// Run the intro Scene
[[CCDirector sharedDirector] runWithScene: [GameScene node]];


//other standard methods for Core Data

//Random data loader

-(void) fetchRandomData: (NSString *) searchInteger
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSLog(@"fetching random data for word size: %@", searchInteger);

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Word" inManagedObjectContext:managedObjectContext];
    [request setEntity:entity];

    //setup predicate
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY %K == %@", @"size", searchInteger];
    [request setPredicate:predicate];

    NSError *error = nil; 
    NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error]; 
    NSLog(@"fetch results count = %i", [fetchResults count]);
    [request release];

    NSMutableArray * results = [NSMutableArray arrayWithCapacity:10];
    NSMutableArray * fetchedIndexes = [NSMutableArray arrayWithCapacity:10];
    //get the total count, randomize selection of 10 results from the list

    int j = 0;
    while (j<10) 
        int index = arc4random() % [fetchResults count];
        //get only unique values
        if ([fetchedIndexes containsObject:[NSNumber numberWithInt:index]] == false)     
            [fetchedIndexes addObject:[NSNumber numberWithInt:index]];

            Word * word = (Word *) [fetchResults objectAtIndex:index];
            //NSLog(@"j = %i, index = %i, wordsize = %@, wordstring = %@",j, index, word.size, word.wordString);
            [results addObject:word];
            j++;

        
    
    //set dataloader 
    [[DataLoader sharedDataLoader] setVeHint:results];

    [pool drain];   


另外,需要提到 EXC_BAD_ACCESS 在 AppDelegate.mm 中的 [pool drain] 调用中。

提前感谢您的帮助。

【问题讨论】:

是的,示例代码将阐明您的问题并更容易找到问题。 生活中很多事情都可能出错...我不知道该选择哪一个... ;-(您如何尝试访问单例中的数据,以及您的单例如何定义。你用那个单例线程安全吗?这些信息应该可以帮助我们帮助你。 大家好,感谢您的快速回复。该代码与 Ray Wenderlich 的 Core Data 教程 ([raywenderlich.com/934/core-data-tutorial-getting-started][1]) 的 Core Data 非常相似。我有一个加载的 sqlite db。然后我有一个方法 getRandomData(),其中包含 NSFetchRequest。在这种方法中,我获取的结果被过滤,这是我设置 Data Loader NSMutableArray 变量的地方。这个核心数据方法几乎没有偏差,所以我不确定这是否能回答你的问题? [1]:raywenderlich.com/934/core-data-tutorial-getting-started 添加了代码 sn-ps - 抱歉耽搁了。 【参考方案1】:

问题可能出在代码的某个地方(我认为它与内存/范围有关,比如发布太早等)。只要您正确地“管理”数据中的每一个部分,您如何访问数据实际上并不重要。

我可以向您展示我是如何进行这种数据管理的。

我通常将其命名为DataManager

DataManager.h

#import <Foundation/Foundation.h>

@interface DataManager : NSObject 
    NSDate *someDate;


@property (nonatomic, retain) NSDate *someDate;

+(DataManager*)sharedInstance;
- (void)loadSettings;
- (void)saveSettings;

@end

DataManager.m

#import "DataManager.h"

static DataManager *dataManagerInstance;

@implementation DataManager

@synthesize someDate = _someDate;

// singleton method
+(DataManager*)sharedInstance 
    if(!dataManagerInstance) 
        dataManagerInstance = [[DataManager alloc] init];
    
    return dataManagerInstance;


- (void)saveSettings 
    // save your data   


- (void)loadSettings 
    // load your data

我希望你明白了……也许你发布一些代码 sn-ps 以便我们可以找出你的单身人士出了什么问题;-)

更新:好的,所以你添加了代码sn-ps,问题显然出在这一行:

[[DataLoader sharedDataLoader] setVeHint:results];

您将 veHint 设置为 results,因此您将覆盖 DataLoader 的私有变量。你不应该那样做,因为results 被释放并且DataLoader 丢失了引用。

您应该编写另一个setter方法,复制results并将元素放入veHint

像这样将results 传递给 DataLoader 后保留它:

[[DataLoader sharedDataLoader] setVeHint:[results retain]];

但是,此解决方案(以及您的解决方案)会造成内存泄漏,因为您在 DataLoader 中保留了 veHint 并在您的委托中覆盖它(您完全失去了对 veHint 的引用)。

【讨论】:

就单例而言,上面 septi 给出的示例几乎是我为单例 DataLoader 类提供的代码,除了我有 NSMutableArray 变量和在 NSMutableArray 中返回特定值的方法. 我认为问题在于您如何返回并管理您传递的对象。你真的应该上传一些代码;-) 作为请求添加的代码 sn-ps - 抱歉耽搁了。【参考方案2】:

Core Data 默认不是线程安全的。如果您尝试在多个线程上使用它,请确保您熟悉 Apple's guidelines。

【讨论】:

谢谢。我不介意 Core Data 不是单例。事实上,我只是拥有从 App Delegate 类访问 sqlite DB 的标准方法。我只想使用从数据库中获取的结果并在单例类中设置变量,以便我的主游戏场景可以访问过滤后的数据。如果这有意义的话。

以上是关于Singleton 类 DataLoader - 在 AppDelegate 中从 Core Data 设置值,但无法访问其他类中的 DataLoader 变量的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 torch Dataloader 获取具有相同类的图片?

pytorch dataset dataloader

pytorch datasets与dataloader阐释说明

Pytorch的Dataset与Dataloader之间的关系

pytorch COCO2017 目标检测 DataLoader

Pytorch深度学习实战3-7:详解数据加载DataLoader与模型处理