简体   繁体   中英

NSMutableArray can't insert a dictionary

can you help me? I´m searching here for a while and testet many things... no solution found!

I have set a NSMutableArray in the .h File:

@interface ViewController : UIViewController

{

NSMutableArray *Transactions;

}

In the .m file in the ViewDidLoad Method I initialized it and load the Array from the UserDefaults:

    Transactions = [NSMutableArray array];
    or
    Transactions = [NSMutableArray new];

    Transactions = [defaults objectForKey:@"transactions"];

Later i add a new Dictionary to it:

[insert setObject:confirmPaymentStatus forKey:@"status"];
[insert setObject:confirmPaymentAmount forKey:@"amount"];
[insert setObject:confirmPaymentDiscription forKey:@"description"];
[insert setObject:timestamp forKey:@"time"];

NSLog(@"%@",insert);

[Transactions addObject:insert];

NSLog(@"Transactions Array:\n%@",Transactions);


[defaults setObject:Transactions forKey:@"transactions"];
[defaults synchronize];

The insert Dictonary is full of data and then i got this from the Log:

2014-02-05 20:56:53.691 PPEasyPay Pro Pro[21907:60b] {
amount = "0.91";
description = "Polaris 123123";
status = COMPLETED;
time = "2014-02-05T11:56:51.248-08:00";

}

2014-02-05 20:56:53.692 PPEasyPay Pro Pro[21907:60b] Transactions Array:
(null)

It sounds like [defaults objectForKey:@"transactions"] is returning null, and therefore you're assigning your array to null. From there, you add an object to your non existent array, and since the array doesn't exist, nothing actually happens. Instead, you should create your array, and only add the objects from the other array to it if they exist.

NSArray *newStuff = [defaults objectForKey:@"transactions"];

transactions = [NSMutableArray new];

if (newStuff) {
    [transactions addObjectsFromArray:newStuff];
}

Side note, your instances should be camelCase starting with a lowercase letter.

Transactions = [NSMutableArray new];

Transactions = [defaults objectForKey:@"transactions"];

When you do that, you are creating a new NSMutableArray, then that array is being discarded when you assign the result of [defaults objectForKey:@"transactions"] to the same variable.

I'd be willing to guess that the result of [defaults objectForKey:@"transactions"] is nil, which is why your array is nil.

Also, by convention, the Transactions variable should begin with a lowercase letter, or even an underscore followed by a lowercase letter.

The problem is that Transactions itself was nil to start with. You then say:

[Transactions addObject:insert];

But this has no effect: sending addObject: to nil still leaves it as nil.

What you need to do is this: after you fetch Transactions from the defaults, look to see if it is nil. If it is, set it to an empty mutable array instead.

Also, please note that this code is utterly stupid:

Transactions = [NSMutableArray array];
Transactions = [defaults objectForKey:@"transactions"];

You set Transactions to an empty mutable array, but then you immediately throw away that empty mutable array and replace it by whatever comes from the defaults (ie nil).

Transactions = [NSMutableArray array];
or
Transactions = [NSMutableArray new];

Transactions = [defaults objectForKey:@"transactions"];

You have several problems here. The first is that what you've written is the object equivalent of this:

int i;
i = 5;
i = 3;

What's i? Well, 3 of course. What does the i = 5 line do? Absolutely nothing. (Except possibly take CPU time, depending on optimization.)

The second problem is that [defaults objectForKey:] is going to return an immutable object.

From Apple's docs for objectForKey: :

Special Considerations

The returned object is immutable, even if the value you originally set was mutable.

The reason this works without error is that objectForKey: returns an id ; you can assign an id to any object variable without an error. But this is like a C pointer cast, not a type coercion. You haven't made the return value a NSMutableArray , you've just shown the compiler you don't care what it is.

What you want is this:

NSArray *readOnlyTransactions = [defaults objectForKey:@"transactions"];
if (readOnlyTransactions == nil) {
    readOnlyTransactions = @[];
}
_transactions = [readOnlyTransactions mutableCopy];

You'll notice I renamed your instance variable to _transactions . This is the convention for instance variables, and you should probably adapt to it.

You can do this more succinctly with the ?: operator, if you're comfortable with using it:

_transactions = [([defaults objectForKey:@"transactions"] ?: @[]) mutableCopy];

What this does:

  1. Read [defaults objectForKey:@"transactions"] .
  2. If that returns nil, use an empty list instead.
  3. Make a mutable copy of it.
  4. Assign the thing to _transactions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM