Value stored during its initialization is never read - xcode

I am trying to create a Game so that I can change its data and save it back. I get two errors that are on the commented lines. Why am I getting these errors. I allocated the Game so I should have to release it correct. Here is my code to save my Game
Game *newGame = [[Game alloc] init];//error 1
newGame = [gamesArray objectAtIndex:gameNumber];
[newGame setTheShotArray:shotArray];
[gamesArray replaceObjectAtIndex:gameNumber withObject:newGame];
NSString *path = [self findGamesPath];
[NSKeyedArchiver archiveRootObject:gamesArray toFile:path];
[newGame release];//error 2
I get error 1 which says Value stored to 'newGame' during its initialization is never read.
The second error says Incorrect decrement of the reference count of an object that is not owned at this point by the caller.
What does this mean? And please don't tell me, you need to read up on memory management and just give me a link. Tell me how to fix the problem please.

Game *newGame = [[Game alloc] init];//error 1
You create a new instance and you own it since you’ve used +alloc.
newGame = [gamesArray objectAtIndex:gameNumber];
You obtain another instance from gamesArray and assign it to the same variable that was used in the previous line. This means that you’ve lost the reference to the previous object and, since you own the previous object, you’re responsible for releasing it. You don’t, so you’re leaking that object.
[newGame release];//error 2
At this point newGame points to the instance via from gamesArray. You do not own it since you haven’t obtained it via NARC, hence you should not release it.
NARC: a method whose name contains new, alloc, copy, or is retain.
Bottom line: you’re leaking the object that you’ve created via +alloc and you’re trying to release an object that you do not own.

Related

NSUserDefaults and serialized data

I am having a problem with our approach to data persistence in our app. It was decided to use NSUserDefaults with NSCoding compliant data model, which I disagree with due to the scale of our app.
The problem I'm seeing is when the data model changes, any attempt to deserialized results in a crash. The app must be uninstalled and reinstalled in order to re-serialize.
Scenario:
User installs app
User does stuff.
Developer decides that a property should be added to one of the serialized objects and pushes an update.
User installs update.
App goes 'kaboom'.
This is happening because the data had been serialized with a different model than it is now attempting to be deserialized as.
Example:
class Contact: NSCoding {
var name
var address
var userId
}
... // NSCoding compliance happens next. This object gets serialized.
Someone decides that Contact needs more stuff:
class Contact: NSCoding {
var name
var address
var userId
var phoneNumber
var emailAddress
}
Attempting to deserialize the Contact object, even though the NSCoding compliance for encoding and decoding has been updated to load and deserialize, causes
fatal error: unexpectedly found nil while unwrapping an Optional value
CoreDataManager.unarchiveUser
Worker.init
So, my question is, how could we possibly avoid this crash from occurring when running an updated version of the app that has a different schema??
You're crashing because,
You are attempting to decodeObject(forKey:) on a key that doesn't exist (because it didn't exist on the class when the object was encoded). This method returns nil.
You are using ! to force-unwrap the result of #1.
As a rule of thumb, if your Swift code crashes on a line that contains a !, there's about a 95% chance that the ! is the direct cause of the crash. If the error message mentions unwrapping an optional, it's a 100% chance.
The documentation for the decodeObject(forKey:) method explains that it may return nil. In your case this is guaranteed to happen if you're upgrading from a previous version of the class and you're decoding a key that you just added.
Your code needs to recognize that there might not be a value for the new properties. The simplest fix is replacing as! with as?. Then you'll get a nil value for the new property. For properties that are not optional, you can add something like ?? "default value" to the end.
You could also use the containsValue(forKey:) method to check if a value exists before trying to decode the key.

Array becomes inaccessible during burn API notification chain

I’m writing an app that burns to optical disks and there’s a strange problem when returning from the burn progress panel.
I call the disk recording setup sheet like this:
let setup_panel = DRBurnSetupPanel()
let passed = UnsafeMutableRawPointer(Unmanaged.passUnretained(self.disk_buckets[current_burn_disk]).toOpaque())
setup_panel.beginSetupSheet(for: self.window, modalDelegate: self, didEnd: #selector(self.burnSetupPanelDidEnd(_:return_code:context_info:)), contextInfo: passed)
disk_buckets is an array of classes each containing a reference to a DRTrack to be burnt - I pass an element so that I can deal with the DRTrack reference later.
After the setup panel is dismissed, the following method is then called:
func burnSetupPanelDidEnd(_ panel: DRBurnSetupPanel, return_code: Int, context_info: UnsafeMutableRawPointer) {
//…. some code ….
var track:DRTrack = self.disk_buckets[self.current_burn_disk].vDRTrack!
NotificationCenter.default.addObserver(self, selector: #selector(self.progressDidEnd), name: NSNotification.Name(rawValue: BTVDiscBurnDidEndNotification), object: nil)
self.objc_panel.presentDiscProgressPanel(self.window, burner: panel.burnObject(), layout: track!)
}
objc_panel is a obj-c singleton that initialises and presents a disc burning progress panel (I did it this way as doing it in Swift is buggy - the progress panel is displayed as a tiny window instead of the default OS one - bug report has been sent to Apple). At the end of the burn objc_panel posts the BTVDiscBurnDidEndNotification notification to let the AppDelegate know it’s finished and so to call:
func progressDidEnd(_ note: Notification?) {
print (“DEBUG count: \(self.disk_buckets.count)")
print (“DEBUG first element: \(self.disk_buckets[0])")
//…. more code ….
}
All goes well until the end of the chain when any attempt to access the first element (or any, for that matter) causes a crash:
2016-10-04 14:01:34.654 DiskSpan[4025:220213] *** -[DiskSpan.BackupDisk retain]: message sent to deallocated instance 0x6000cafc0f40
(BackupDisk being the class that populates the array)
However, the first line prints out a correct count of the array i.e. 1. So how come I can't access anything in the array during a notification post?
EDIT: I tried appending a dummy item to the array before reading it back and still the crash only occurs when trying to read the array - not write to it.
It should be noted that this worked under Swift 2 and has only become a problem since Swift 3!
It turns out to be a retention problem. After the call to the obj-c class to start the setup window for burning, the elements in disk_buckets are all over-released. It was a hack but I enumerated over the elements and assigned them to a new array just before calling the setup panel.

PFUser currentUser saveInBackgroundWithBlock completes succeeded without even trying

I am trying to alter the logged in user. I make my changes as usual, and I call:
[[PFUser currentUser] saveInBackgroundWithBlock:^(BOOL succeeded, NSError *PF_NULLABLE_S error){
if(succeeded){
NSLog(#"Saved user successfully.");
}else{
NSLog(#"Unable to save user: %#", error);
}
}];
It saves successfully, but my changes are gone. Just before saving, my user objects has this key:
.meta.acceptsAllMessages = 1. The moment save completion block returns, that key is gone. `(meta is my generic JSON object at user, and other values in meta key are retained with no problem). My changes aren't also reflect to the server side too.
The first suspect was the beforeSave trigger, however there's absolutely nothing related to meta keys in my trigger, so that's not the case. Why would this happen?
UPDATE: There seems to be a problem deeper down. I was saving something else entirely, and ran into the same issue. I've enabled airplane mode, and I wanted to save my current user, and it called the completion handler immediately, with succeeded set to YES and error set to nil without an internet connection. I've double checked that I'm using saveInBackgroundWithBlock: and not saveEventually. Why does this happen?
Okay, I've found the solution.
I was adding an object to the array inside my user object, without assigning the property itself. In the latest instance, I was doing something like:
[[PFUser currentUser][#"myArray"] addObject:#"something"];
[[PFUser currentUser] saveInBackground...];
Because I was not assigning any object itself, [my assumption is that] Parse thought that my user object was not dirty, and it completed immediately without even trying to save. I've solved the problem like this:
NSMutableArray *array = [PFUser currentUser][#"myArray"];
[array addObject:#"something"];
[PFUser currentUser][#"myArray"] = array;
The last line is the key. I'm assigning to the "myArray" field of Parse object, which causes Parse to mark my user dirty. Then, when I save, because it is dirty, it actually saves my user to the server, and it works.

cocoa; What is the leak in this code?

NSMutableArray *tempData=[[NSMutableArray alloc]init];
TBXMLElement * city = [TBXML childElementNamed:#"city" parentElement:root];
while(city!=nil){
if([TBXML valueOfAttributeNamed:#"name" forElement:city]!=nil){
NSString *tempDataHolder=[NSString stringWithFormat :#"%#,%#",[TBXML valueOfAttributeNamed:#"name" forElement:city],[TBXML valueOfAttributeNamed:#"country_name" forElement:city]];
[tempData addObject:[tempDataHolder copy]];
[tempDataHolder release];
}
city = [TBXML nextSiblingNamed:#"city" searchFromElement:city];
}
tableData=[tempData copy];
[tableCities reloadData];
[tempData release];
Instruments with Memory leaks says there is a leak of multiple NSCFStrings,i have been trying to figure it out for a while, any help is highly appreciated.
Thanks
edit: The above set of code runs a few times, and i have a bunch of leaks referring to NSCFString - NSPlaceholderString. I am releasing tempDataHolder almost immediately and the rest of the variables are being released as well. I cant pin point on where the leak is.
Copied objects need to be released by the owner. That is, the copy method returns a new object that has a retain count of 1. In your situation, the culprit seems to be this line:
[tempData addObject:[tempDataHolder copy]];
Containers retain their elements, but the copied object already has a retain count of 1 before being inserted in the array. The copied object is therefore leaking.
Simply adding tempDataHolder in your array (not a copy) should solve it.
Also, tempDataHolder is an auto-released object and shouldn't be released explicitly.

How to check if self.navigationController is nil

In the following code, I am able to check with the debugger the values of self and childView.
[self.navigationController pushViewController:childView animated:YES];
However, I am not able to see the value of self.navigationController. How can I check if it is nil?
Just add the line:
UINavigationController* navController = self.navigationController;
And then set a breakpoint, or whatever else you want to do.
The reason is because navigationController is a property, so you can't just examine it; you would have to send the property's owner a getter message. In the debugger, that's pretty expensive, especially if it crashes or otherwise fails, plus it could always have side effects (e.g., faulting in a Core Data object, lazy-loading something, or changing some state in another ivar), so the debugger will not do this casually.
You must explicitly request the message using the Debugger Console:
po [self navigationController]
(I don't know whether it will let you use property-access syntax there. There's no difference between them, which is the root of the problem: A property access is an Objective-C message, which, as I described above, is why the debugger won't do one unless you specifically tell it to.)
You could always just do something like (self.navigationController == nil).

Resources