如何向单例NSMutableArray中添加对象

3

我曾经将从服务器下载的数组数据存储起来。

但是我无法将它们保存在单例数组中。

似乎没有访问对象。

为什么ulatitude、ulongitude、uaccuracy、uplacename都是nil?...

在.h文件中

#import <Foundation/Foundation.h>
@interface LocationData : NSObject
{
    NSMutableArray *ulatitude;
    NSMutableArray *ulongitude;
    NSMutableArray *uaccuracy;
    NSMutableArray *uplacename;
}
@property (nonatomic, retain) NSMutableArray *ulatitude;
@property (nonatomic, retain) NSMutableArray *ulongitude;
@property (nonatomic, retain) NSMutableArray *uaccuracy;
@property (nonatomic, retain) NSMutableArray *uplacename;
+ (LocationData*) sharedStateInstance;
@end

在 .m 文件中

#import "LocationData.h"

@implementation LocationData

@synthesize uaccuracy;
@synthesize ulatitude;
@synthesize ulongitude;

+ (LocationData*) sharedStateInstance {
        static LocationData *sharedStateInstance;

        @synchronized(self) {
            if(!sharedStateInstance) {
                sharedStateInstance = [[LocationData alloc] init];
            }
        }
        return sharedStateInstance;
}
@end

使用

[manager POST:urlStr parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject)
    {

                 NSLog(@"%@",responseObject);

                 // json response array
                 if ([responseObject isKindOfClass:[NSArray class]]) {

                     NSArray *responseArray = responseObject;
                     NSDictionary *responseDict = [[NSDictionary alloc] init];

                     LocationData* sharedState = [LocationData sharedStateInstance];

                     for(NSUInteger i=0; i < responseArray.count; i++)
                     {
                         responseDict = [responseArray objectAtIndex:i];

                         double dlat = [[responseDict objectForKey:@"lat"] doubleValue];
                         double dlng = [[responseDict objectForKey:@"lng"] doubleValue];

                          [[sharedState ulatitude] addObject:[NSString stringWithFormat:@"%f",dlat]];
                          [[sharedState ulongitude] addObject:[NSString stringWithFormat:@"%f",dlng]];
                          [[sharedState uaccuracy] addObject:[responseDict objectForKey:@"rad"]];
                          [[sharedState uplacename] addObject:[responseDict objectForKey:@"place_name"]];
}

为什么要定义实例变量,并且为什么合成3个属性(而非零个)? - Avi
此外,除非您不使用ARC,否则应将属性定义为“strong”而不是“retain”。 - Avi
5个回答

7

您总是需要初始化您的数组。在尝试向数组添加内容之前,应该在某个地方执行初始化操作:

arrayName = [[NSMutableArray alloc] init];

否则,您将始终出现错误,因为它们尚未初始化。
在您的情况下,您应该像这样覆盖LocationData init函数:
- (instancetype)init {
    self = [super init];
    if (self) {
        self.yourArrayName = [[NSMutableArray alloc] init];
        // And so on....
    }
    return self;
}

2
"Somewhere" 被初始化为 init - trojanfoe

1
你需要正确地初始化对象。基本上,你的成员变量("ivars")指向了空值("nil")。
在你的.m文件中添加这个初始化器即可完成任务。
-(instancetype)init {
    if ((self = [super init])) {
                    self.accuracy = [NSMutableArray array];
                    self.latitude = [NSMutableArray array];
                    self.longitude = [NSMutableArray array];
                    self.uplacename = [NSMutableArray array];
    }
    return self;
}

作为单例模式,我更倾向于以下方式:
+ (LocationData*) sharedStateInstance {
    static LocationData *sharedStateInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        sharedStateInstance = [[LocationData alloc] init];
    });
    return sharedStateInstance;
}

尽管单例模式可能并不像人们常说的那样糟糕,但我认为这并不是一个好的使用方式。然而,你的具体问题与该设计选择无关。

1
不要忘记这是手动引用计数。建议使用self.array =,并且无论类是否为单例,您都应该在dealloc方法中展示如何处理它(因为某个时刻可能会有人决定将其更改为非单例)。 - trojanfoe
我一直认为除非有特别说明,否则ARC是今天的标准。 - Eiko
1
@property (nonatomic, retain) 告诉了不同的信息。 - trojanfoe
@trojanfoe 很好的发现,我漏掉了那个。已经修复了。 :) - Eiko

0

尝试这个代码。为你的NSMutableArrays编写getter。

#import <Foundation/Foundation.h>
@interface LocationData : NSObject

@property (nonatomic, retain) NSMutableArray *ulatitude;
@property (nonatomic, retain) NSMutableArray *ulongitude;
@property (nonatomic, retain) NSMutableArray *uaccuracy;
@property (nonatomic, retain) NSMutableArray *uplacename;
+ (LocationData*) sharedStateInstance;
@end


#import "LocationData.h"

@implementation LocationData

@synthesize uaccuracy = _uaccuracy;
@synthesize ulatitude = _ulatitude;
@synthesize ulongitude = _ulongitude;

+ (LocationData*) sharedStateInstance {
        static LocationData *sharedStateInstance;

        @synchronized(self) {
            if(!sharedStateInstance) {
                sharedStateInstance = [[LocationData alloc] init];
            }
        }
        return sharedStateInstance;
}


-(NSMutableArray*)uaccuracy
{
    if(_uaccuracy == nil)
    {
        _uaccuracy = [[NSMutableArray alloc]init];
    }
    return uaccuracy;
}

-(NSMutableArray*)ulongitude
{
    if(_ulongitude == nil)
    {
        _ulongitude = [[NSMutableArray alloc]init];
    }
    return ulongitude;
}

-(NSMutableArray*)ulatitude
{
    if(_ulatitude == nil)
    {
        _ulatitude = [[NSMutableArray alloc]init];
    }
    return ulatitude;
}

-(NSMutableArray*)uplacename
{
    if(_uplacename == nil)
    {
        _uplacename = [[NSMutableArray alloc]init];
    }
    return uplacename;
}
@end

将属性与其默认名称合成,然后还有一堆不同命名的ivar没有被使用,这样做毫无意义。 - Eiko
尽管它可以工作,但不会导致任何错误。此外,您可以删除@synthesis。它也可以工作。我只是在合成中提到了这一点,以便他可以了解ivar的概念。否则,他会想知道这个“_”符号来自哪里。您可以看到,我没有为uplacename属性使用ivar。 - Shehzad Ali
不行。我知道在给定的上下文中它应该能够工作,但它只是糟糕的。在你的接口文件中声明的变量根本没有被使用 - 只是误导性的死存储。而且它为未来引入了许多新的错误可能性,因为编写看起来完全合法并且可以编译的代码却不能按照应有的方式工作是微不足道的。 - Eiko
哦,抱歉我没有检查接口。我只是从问题中复制了它。 - Shehzad Ali
这些属性已被移除。 - Shehzad Ali
显示剩余3条评论

-1

你没有分配/初始化任何数组...

你可以在单例创建方法中创建它们

+ (LocationData*) sharedStateInstance {
        static LocationData *sharedStateInstance;

        @synchronized(self) {
            if(!sharedStateInstance) {
                sharedStateInstance = [[LocationData alloc] init];
                sharedStateInstance.ulatitude = [[NSMutableArray alloc] init];
                // (add others...)
            }
        }
        return sharedStateInstance;
}

1
不应该。init方法应该分配和初始化数组。 - trojanfoe
这里和init中没有区别... 这是一个单例类,因此必须通过+ (LocationData*) sharedStateInstance方法传递。 - meronix
你的回答肯定可以解决OP的问题,但是它做得很差。 init 是初始化类实例的地方,无论存在多少个实例。 - trojanfoe
你的回答肯定会解决OP的问题...那么为什么要踩我的回答呢?很明显,在标题问题中,我们正在讨论一个单例类,并且通常(但可能有例外),拥有一个单例类和该类的其他实例并不是一个好主意。 - meronix
@trojanfoe:好的,抱歉我曾经这么想过。 - meronix

-1
请将您的LocationData.m文件替换为下面的代码,这样就可以正常工作了。您必须先分配和初始化数组才能向其中添加对象。
+ (LocationData*) sharedStateInstance {
            static LocationData *sharedStateInstance;
                    @synchronized(self) {
                    if(!sharedStateInstance) {
                        sharedStateInstance = [[LocationData alloc] init];
                        uaccuracy = [[NSMutableArray alloc]init];
                        ulatitude = [[NSMutableArray alloc]init];
                        ulongitude = [[NSMutableArray alloc]init];
                        uplacename = [[NSMutableArray alloc]init];
                    }
                }

            return sharedStateInstance;
    }

这将始终有效,在共享实例中,您可以分配和初始化数组,这将保持不变,并且不会始终分配和初始化为在共享实例中编写的那样。 - Vatsal Raval
你确定吗? - trojanfoe
是的,因为它写在@synchronized(self)内部,而且它只会分配一次,当共享实例被分配时,每当应用程序重新启动时,它都会被分配一次。 - Vatsal Raval
那么你可以从类方法中访问属性 uaccuracy 吗? - trojanfoe
嗯,该怎么说呢...它甚至在第一次编译时都无法通过,因为有四个变量根本没有声明。 - Eiko
是的,通过使用 LocationData* sharedState = [LocationData sharedStateInstance]; 然后 sharedState.uaccuracy,您可以访问数组。 - Vatsal Raval

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接