Memory management issue about Swift for-loop - ios

I take over some legacy code, and there's a code snippet like this
let albumGroups = data.getJSONArray("groups")
let groupNum = albumGroups.length()
var album: JSONObject
for i in 0..<groupNum
{
album = albumGroups.getJSONObject(i)
orderSummary.album.name[i] = album.getString("name")
}
It runs without any issue when the app is built in Debug mode.
But if it is built in Release mode, it crashes at album.getString("name") when i is 1. The error shows that the album variable was deallocated.
I tried running the app with Address Sanitizer flag enabled.
My question is, as far as I know, the album variable is out of the loop's scope, why it was deallocated after the first loop ended?

Check that orderSummary.album isn't a weak reference. If it is, the Album you initialize on line 1 is destroyed immediately, which would explain the crash when you attempt to set orderSummary.album.name[i].

Related

ambiguous for type lookup in this context when -com.apple.CoreData.ConcurrencyDebug 1 is active

The code below runs perfectly fine when I have the above parameter turned off in my Scheme. When it is turned on I get a 'Group' is ambiguous for type lookup in this context crash error. on the line "let currentGroup = context.object(with: groupID) as? Group"
I've checked my project and there is no duplicate reference to Group NSManagedObject.
let context = CoreDataStack.shared.newPrivateContext()
if reset {
AppDefault.current_ListGroup = nil
}
if let groupID = AppDefault.current_ListGroup,
let currentGroup = context.object(with: groupID) as? Group {
return currentGroup.objectID
} else {
Can someone help me figure out why it works with the .ConcurrencyDebug 1 off but crashes when it is on?
Thanks in Advance
When concurrency debugging is on, the app will crash any time you break the concurrency rules. Breaking the rules on its own doesn't always crash the app-- but with debugging enabled, you're saying that you want to crash as soon as you break the rules, even if the app would work normally without debugging. This is a good thing, because breaking the rules will probably make the app crash eventually even if it doesn't happen right now.
How you're breaking the rules here is:
You're creating a new private queue context with newPrivateContext.
You're using that context without calling perform or performAndWait.
With a private queue context, you must use one of those functions whenever you use the context. Really the only time you don't have to use one of those is if you're using main queue concurrency and you know that your code is running on the main queue. You can sometimes get away with not doing that, if everything is just right, but concurrency debugging will stop you immediately. That's what you're seeing.

AVPlayer removing observer crash in Swift 2.2

I have a video app that I built a while back in Swift 1 and I've been trying to migrate to Swift 2.2. It all (finally) works apart from a weird crash to do with observers.
func removeObservers()
{
print("REMOVING OBSERVERS")
if ( !self.is_image && self.player != nil ) {
if (self.player?.observationInfo != nil) {
self.player?.removeObserver(self, forKeyPath: "currentItem.status")
self.player?.removeObserver(self, forKeyPath: "readyForDisplay")
}
}
NSNotificationCenter.defaultCenter().removeObserver(self)
}
This worked previously using SwiftTryCatch but with the lines in place crashes with "'Cannot remove an observer for the key path "readyForDisplay" from because it is not registered as an observer.'" OR with that an observer is registered on a deallocated object if I comment it out.
If I add a do { } catch {} to it I get an error that "this does not throw" and it just crashes the same. How do I go about putting this in some form of try-catch format?
In Swift 2, the libs got annoyingly strict about errors that are truly unexpected (which throw) versus errors that the programmer could have prevented (which do not throw, but just crash your app).
(I’m not a fan of this distinction, or at least not of all the specific decisions Apple made about which errors fall in which category. The JSON API verges on the nonsensical in this department. But…we work with the API we’ve got.)
The NSKeyValueObserving docs say:
It is an error to call removeObserver:forKeyPath: if the object has not been registered as an observer.
“It is an error” is Apple code for “you are responsible for never doing this, and if you do, your app will crash in an uncatchable way.”
In these situations, there is usually an API call you can make to check the validity of the thing you’re about to do. However, AFAIK, there’s no KVO API call you can make to ask, “Is X observing key path Y of object Z?” That means you have three options:
Figure out why you’re trying to remove an observer from something you’re not observing, and prevent that using your program’s own internal logic.
Keep a weak instance var for “player I’m observing,” and check that for a match before attempting to remove the observer.
Add self as an observer before removing it. (I’m pretty sure that a redundant add is OK.)
Since you are making a call removeObserver(self) at the end of the method, why cant you uncomment above code? Because removeObserver(self) removes all the observers if registered any. I hope this solves your issue.
NSNotificationCenter.defaultCenter().removeObserver(self)
status is a property of either AVPlayer or AVPlayerItem.
readyForDisplay is a property of AVPlayerLayer

EXC_BAD_ACCESS on nil checking optional in Swift

EDIT 2: After changing some completely unrelated code the crash happens again. Even if I try to revert the code changes, it crashes again.
EDIT: After updating to iOS 9.2 (from 9.1) it works without any problem again.
The following code gives me an EXC_BAD_ACCESS on the nil check:
if(self.imageViews != nil){
for (_,element) in self.imageViews!.enumerate(){
element.removeFromSuperview()
}
}
The property is defined as follows:
class ImageAdditionalContent : AdditionalContentView {
var imageViews : [UIImageView]?
Even if I try to first assign an empty array to it, it gives me an EXC_BAD_ACCESS on the assignment:
self.imageViews = []
Even more interesting is, that it worked perfectly a day ago. If I remove the whole code, run the app, quit it, add the code again and run it again, it crashes on the for loop for the first time and afterwards again on the nil check.
I would take advantage of optionals here. As to your EXC_BAD_ACCESS I would check not just the status of the UIImageView array but self. Set a breakpoint before the assignment and see what's going on. If this worked fine a day ago I would also look at what code changes have happen in your project.
if let elements = self.imageViews {
for element in elements {
element.removeFromSuperview()
}
} else {
print("self.imageViews is nil! \(self.imageViews)")
}

Why is my crashing and saying EXC-BAD_ACCESS while trying to show a GKPeerPickerController(ARC is on)

Recently I have come across a problem in an app that I am developing. The app is crashing with EXC_BAD_ACCESS. This doesn't make sense because auto-reference-counting is turned on.
In the app, I have a button that is linked to an IBAction that displays a GKPeerPickerController.
-(IBAction)showPicker:(id)sender
{
picker = [[GKPeerPickerController alloc ] init];
picker.delegate = self;
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[picker show];
}
This doesn't make sense because if I try to manage the memory with calls such as release, it will give me an error saying that ARC disables that call. So as far as I know there is nothing I can do about it. When it crashes, the EXC_BAD_ACCESS is on the line that allocates and initializes the GKPeerPickerController.
Does this only happen the second time you try to launch the GKPeerPicker?
EXC_BAD_ACCESS is thrown when your app tries to access a memory location which it doesn't 'own'. This can happen in numerous different ways, even with ARC, which makes it a hard crash to diagnose.
Check out this question for e.g. EXC_BAD_ACCESS (SIGSEGV) crash - using NSZombies could be a way to track what's going on.
However, a little more understanding of what's going on might help you to understand this crash and fix it.
The first question is - how is it possible to get EXC_BAD_ACCESS when we're merely assigning a newly allocated object? Well - the 'magic of ARC' is coming in to play here... That simple assignment statement is assigning a new object to an instance variable. The compiler will see that and say - Ah... that ivar might already have an object assigned to it, in which case I'd better release it... So it will add some code for you to check for nil and release the ivar, before it assigns the new value.
So - I find it unlikely that the alloc/init is causing your problem, and more likely that it's whatever is currently stored in your picker ivar... What happens if you make picker a local variable instead of an ivar?
-(IBAction)showPicker:(id)sender
{
GKPeerPickerController *localPicker = [[GKPeerPickerController alloc ] init];
localPicker.delegate = self;
localPicker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[localPicker show];
}

Monotouch + UIWebView = Random Crashes

I'm using the latest stable releases of Mono/Monotouch/MonoDevelop on a iOS 5.0 iPhone and iPad. I have a UIWebView that in the emulator never crashes however randomly on the actual devices it crashes on EXC_BAD_ACCESS. Based on everything I've read with UIWebViews that most likely occurs when the UIWebView gets disposed before it finishes loading.
Here is the code I am using in my ViewDidLoad():
var urlAddress = BASE_URL + _page;
var nsURL = new NSUrl(urlAddress);
var nsURLRequest = new NSUrlRequest(nsURL);
_webView.Tag = 10;
_webView.ScalesPageToFit = true;
_webView.AutosizesSubviews = true;
_webView.LoadStarted += HandleWebViewLoadStarted;
_webView.LoadFinished += HandleWebViewLoadFinished;
_webView.LoadRequest(nsURLRequest);
this.Add(_webView);
Any ideas why it would crash on the actual device randomly, but never in the emulator?
I would need to see the crash details and a but more of source code to be 100% certain but I do believe it's caused because your NSUrlRequest instance is declared as a local variable. Promote this variable into a field of your type should solve this.
The instance could still be required once the method is completed it's execution. However at that time it's not referenced anymore and the garbage collector can collect it anytime. If collected then you'll likely get a crash like you mentioned.
The fact it does not occur on the simulator is likely caused because it's faster (than the device) and the code can complete before the GC collect that instance. IOW it could crash it's just a timing thing that makes it work most of the time on the simulator and almost never on devices.

Resources