James Perih
James Perih

Reputation: 1384

ARC causing me pain

I realize there are tutorials, but they never seem to go deep enough.

Right now, I have an app that allows invoicing. However, due to the dynamic nature of the data types, I keep this as a sharedObject in a main user class, not a class on its own. Each invoice is contained in an NSMutableDictionary, which can contain as many or as little member objects as possible. There are so many different types of invoices that we found it best to do this way.

Problem we have now, is when one invoice is done, and another created, the UI for those items seem to retain the previous invoice values, even though at the end of the invoice, I set the NSMutableDictionary to nil.

Basic process: through several view controllers in varying sequence, I set the value input into NSTextFields as NSStrings as values for keys in the main NSMutableDictionary, and move to the next appropriate screen.

These NSTextFields are declared as non atomic, strong.

Their values are set with

[myNSMutableDictionary addObject:textField.value forKey:@"thisValue"];

Because ARC, nothing is released explicitly, and I've made careful to not alloc and init anything.

Each screen onDidShow assigns text fields with its respective value in the NSMutableDictionary.

What I expect, is during the current invoice no text fields will contain old values, and on successfully submitting the invoice to the cloud service, the entire invoice is blanked out. Never stored in device (except when backgrounded).

What I get, as a result of setting the NSMutableDictionary to nil, is that screens seem to retain either their previous values, sometimes nil, but most often the value of the previous invoice.

Is there a convenience method to set all members to nil, or should I:

Declare the NSMutableDictionary as nonatomic, strong in my sharedManager, Alloc / Init the invoice NSMutableDictionary when I want a new one, but declare all IBOutlets as nonatomic, weak (so assigns in one direction or the other do not retain), and ensure if I do need to alloc an object to be added to the NSMutableDictionary, that they are declared somehow also as weak? It may occur that eg, I need to store an NSArray in the NSMutableDictionary, I

[myArray alloc] initWithObjects:value1, value2, nil]];

What I'm saying, is even though I set the invoice as nil, value1 and value2 seem zombied, but reassigned after a second pass-through the code.


Sample code: in User.h, I have a property:

@property (nonatomic, strong) NSMutableDictionary *currentInvoice;

in User.m, I instantiate during an 'init' method:

currentInvoice = [[NSMutableDictionary alloc] initWithCapacity:1];

When a new invoice is created (in InvoiceViewController.m):

User *userInfo = [User sharedManager];
userInfo.currentInvoice = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   _clientId, @"clientId",
                                   _clientType, @"clientType",
                                   _txtClientName.text, @"clientName",
                                   keyContactName, @"keyContactId",
                                   orderTypeNum, @"orderType",
                                   _keyContact.text, @"keyContact",
                                   _problemDescription.text, @"problemDescription",
                                   _dateOfService.text, @"startDate",
                                   _startTime.text, @"startTime",
                                   _endTime.text, @"endTime", nil];

(Btw, I think i solved my problem, as i never re-instantiate a new userInfo.currentInvoice, just copy over the old one, it's members not mentioned here are likely still in tact)

Elsewhere in InvoiceViewController.m, a method that essentially cancel's the invoice process:

- (IBAction) dismissViewController:(id)action: {
     User *userInfo = [User sharedManager];
     userInfo.currentInvoice = nil;
}

In InvoiceStepTwoViewController.m, another controller with other aspects of the same invoice:

@property (strong, nonatomic) IBOutlet UILabel *clientName; // in the .h, of course
@property (strong, nonatomic) IBOutlet UITextView *textView; // in .h, used to capture data

- (void)viewDidAppear {
    User *userInfo = [User sharedManager];        
    _clientName.text = [userInfo.currentInvoice objectForKey:@"clientName"];
}

After a bit of changing and capturing values,

- (IBAction)finishStepTwo:(id)sender {
    [userInfo.currentInvoice addEntriesFromDictionary:[NSDictionary dictionaryWithObjectsAndKeys:_textView.text, @"nerdspeak", nil]]; // so that NSMutableDictionary.currentInvoice objectForKey:@"nerdspeak" will contain _textView.text's value... but will currentInvoice own this object now? Will invoiceStepTwoViewController retain this as long as is possible?
}

My question; are my viewControllers (there are many more) unintentionally retaining values due to @property (strong, nonatomic) and never letting go (because viewDidUnload never seems to be called), and that's why data doesn't seem to reinit, OR is it because when I do add a new invoice, I don't actually reinstantiate, but just copy over other values?

Upvotes: 1

Views: 161

Answers (1)

Alfie Hanssen
Alfie Hanssen

Reputation: 17094

Without much code to go from it looks like this doesn't have anything to do with ARC, therefore modifying the @property declarations (i.e. strong to weak) will have no affect.

It sounds like your "datasource" from which your UI is populated is an NSMutableDictionary. And it sounds like you're setting this dictionary to nil and then assigning it to a new NSMutableDictionary that contains a new invoice's data. This sounds solid.

However changing the value of the NSMutableDictionary will not automatically modify the values of your UI elements (e.g. self.textLabel.text). You will need a method that functions similarly to UITableView's reloadData method in that you invoke it when you update your datasource (i.e. your dictionary) and it manages updating the UI accordingly.

So, doesn't seem like this is ARC related, but related to the natural behavior of objects like UILabel.

Hope this helps...

Upvotes: 2

Related Questions