I have an application which has a collection view full of videos and images. When you tap on one of them you segue to a full screen to view the media. When I tap a image It works as needed. But when I run my application and tap one of those videos I get the error shown bellow:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x8000000000000010)
I get this here:
class AppDelegate: UIResponder, UIApplicationDelegate {
Is this possibly due to memory problems?
What is happening and how do i fix this?
I have looked here but was unable to solve it.
I have found that the fail actually occurs when the bellow function is called.
func getAndShowMedia(post: Post) {
if post.media[numberMedia].image != nil {//here is still works, I am assuming this line is the line which actualy fails
print("imageooooo")//When setting break point here it will crash
mediaView.image = nil
mediaView.image = (post.media[numberMedia].image)!
} else {
mediaView.layer.removeFromSuperlayer()
let videoURL = post.media[numberMedia].videoURL
let player = AVPlayer(url: videoURL! as URL)
let playerLayer = AVPlayerLayer(player: player)
print("videooooooo")
playerLayer.frame = mediaView.bounds
mediaView.layer.addSublayer(playerLayer)
player.play()
}
}
Here:
func loadOtherData() {
getAndShowMedia(post: selectedPost!)
}
Please check your code and tell me where be crash.
I read your code and assume happening crash, i write be below point and check the debug mode.
post.media[numberMedia].image you check is not nil please there case use if let statement.
post.media[numberMedia].videoURL is geting in your model URL object that will happening crash.
mediaView.layer.removeFromSuperlayer() i don't understand this code you have remove layer but you add sublayer mediaView.layer.addSublayer(playerLayer) then remove sublayer. Check your sublayer is available then remove sublayer, not remove mediaView layer.
use this code remove layer.
mediaView.layer.sublayers?.forEach({ $0.removeFromSuperlayer() })
I hope this code will be work.
From the Breakpoint menu in Xcode, press the '+' button at the bottom left then add an exception breakpoint. This will show you exactly where your app is crashing and you'll be able to debug it properly.
You have a few forced unwraps there that may be nil, you should avoid that.
Related
In a SceneKit project, the following method is intermittently (but consistently) crashing with EXC_BAD_ACCESS. Specifically, it says Thread 1: EXC_BAD_ACCESS (code=1, address=0x0).
contactTestBetween(_:_:options:)
The method is called from inside SceneKit's SCNSceneRendererDelegate method. It's also being run on the main thread because otherwise, this code crashes even more often. So, here's the greater context:
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
var ball = self.scene?.rootNode.childNode(withName: "ball", recursively: true)
var ballToFloorContact: [SCNPhysicsContact]?
let theNodes: [SCNNode]? = self.scene?.rootNode.childNodes.filter({ $0.name?.contains("floor") == true})
let optionalWorld: SCNPhysicsWorld? = self.scene?.physicsWorld
DispatchQueue.main.async {
if let allNodes = theNodes {
for i in 0..<allNodes.count {
let n = allNodes[i]
if let b = n.physicsBody, let s = ball?.physicsBody {
ballToFloorContact = optionalWorld?.contactTestBetween(b, s)
}
}
}
}
}
The SCNSceneRendererDelegate is set in viewDidLoad:
scnView.delegate = scnView
Additional info:
When the crash occurs, optionalWorld, b, and s are all properly defined.
I originally had the call to filter located inside the DispatchQueue, but it was causing a crash that seemed identical to this one. Moving that line outside the DispatchQueue solved that problem.
Question: Any idea what might be causing this crash, and how I might avoid it? Am I doing something wrong, here?
Thanks!
UPDATE: I tried adding the following guard statement to protect against a situation where the contactTestBetween method is, itself, nil (after all, that seems to be what Xcode is telling me):
guard let optionalContactMethod = optionalWorld?.contactTestBetween else {
return
}
However, after some additional testing time, contactTestBetween eventually crashed once again with EXC_BAD_ACCESS on the line guard let optionalContactMethod = optionalWorld?.contactTestBetween else {. I truly do not understand how that could be, but it be. Note that I tried this guard paradigm both with and without the presence of the DispatchQueue.main.async call, with the same result.
I did two things, here:
I added Accelerometer and Gyroscope to the UIRequiredDeviceCapabilities key in my Info.plist file. I did this because my game uses Core Motion, but I had neglected to include the necessary values.
On a hunch, I replaced the SCNSceneRendererDelegate method renderer(_: SCNSceneRenderer, updateAtTime: TimeInterval) with the alternative method renderer(_: SCNSceneRenderer, didRenderScene: SCNScene, atTime: TimeInterval).
Since doing these things, I haven't been able to reproduce a crash.
An alternative unsafe fix is
try! await Task.sleep(nanoseconds: 1)
somewhere before invoking contactTestBetween().
This answer sits here as a warning to anyone who might want to use async/await as a fix or is inadvertendly using some await (any kind of await works) to break out of the run loop which somehow makes debugging EXC_BAD_ACCESS nearly impossible because it will get triggered rarely enough.
I know from experience that if the above fixed a race then races WILL still happen especially and mostly with CPUs running at 100% and actually I got contactTestBetween to crash once after many tries.
I have no clue what's going on behind the scenes or how to synchronize with physicsWorld.
#West1 solution is still the best if it works as advertised.
Many questions on this topic, but most are so old the answers no longer apply due to both Swift and iOS having evolved so much since they were posted. The few that look helpful at first glance don't actually tell me anything I haven't already figured out, and haven't done anything to help me fix my incarnation of the problem, despite appearing to be nearly identical to the problem I'm having.
Aside from AVAudioPlayerDidFinishPlaying never being called (And therefore leaving "other sounds" being made by the device "ducked" until the app is totally shut down) the code below functions exactly as expected, in both Simulator and on a physical iPhone 7 Plus running iOS 13.3. If it makes a difference, I'm coding to Swift 5.1, targeting iOS 13.3, in Xcode 11.3, on a rig that runs Catalina (10.15.2).
Here's the "broken" code:
import Foundation
import AVFoundation
class NoiseMaker: NSObject, AVAudioPlayerDelegate {
var ourSession = AVAudioSession()
var ourPlayer = AVAudioPlayer()
func playSound(sound: String) {
print("Entered NoiseMaker.playSound(sound: \(sound))")
let theURL: URL = Bundle.main.url(forResource: sound, withExtension: "mp3")!
try!ourSession.setCategory(AVAudioSession.Category.ambient, options: AVAudioSession.CategoryOptions.duckOthers)
try!ourSession.setActive(true)
ourPlayer.delegate = self
ourPlayer.prepareToPlay()
do {
ourPlayer = try AVAudioPlayer(contentsOf: theURL)
ourPlayer.play()
} catch let theError as NSError {
print("Couldn't load \(sound).mp3 - Error \(theError)")
}
}
// MARK: - AVAudioPlayer delegate methods
// Never gets called - Other sound sources remain "ducked" until the app is completely shut down.
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("Arrived in audioPlayerDidFinishPlaying")
try!ourSession.setActive(false)
}
func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
print("Decoding error from AVAudioPlayer: \(error!.localizedDescription)")
}
}
As noted, everything works as expected - EXCEPT for my audioPlayerDidFinishPlaying method never being called, meaning I never get a chance to "unduck" other sounds that might be playing. (although everything "unducks" as soon as the app is completely shut down)
Why? How am I screwing up what seems to be a nearly trivial task?
I see the problem, you set self as the delegate but then you change the reference to a new instance of AVAudioPlayer
You should set the delegate after creating new instance in here
ourPlayer = try AVAudioPlayer(contentsOf: theURL)
ourPlayer.delegate = self
ourPlayer.play()
I get w weird crash related to observing AVPlayer.timeControlStatus in iOS 13. It's not happening in iOS 12.
Here's the code for setting the observer up:
// stored in View Controller
private var playerStateObservation: NSKeyValueObservation?
#objc var player : AVPlayer?
// setting KVO after initialising AVPLayer
playerStateObservation = observe(\.player?.timeControlStatus) { [weak self] (object, change) in
let playing = self?.player?.timeControlStatus == .playing
self?.showPlayIcon(playing)
}
And here the function to stop observation. It's called in ViewController deinit.
func cleanUpObserver() {
playerStateObservation?.invalidate()
playerStateObservation = nil
}
The crash occurs in following situation:
Open ViewController with AVPlayer and start observation.
Go back to previous ViewController.
Dismiss the app to the background.
Bring back the app to the foreground.
Crash: Thread 1: EXC_BAD_ACCESS (code=1, address=0x2b1bc593c)
Here's the callstack of the crash.
Looks like the AVPlayer is trying to send notification to a observer that should already be invalidated and released from memory. Did anyone have a similar issue?
viewWillDisappear will be better place to remove observations dude.
I have an app, that is for many years in the AppStore and runs without any crashes (last deployment target iOS 12.4). I have some code for playing a sound on certain events in the app.
Now I tried to upgrade my app for iOS 13 and without changing any code related to that “playSound” thing, I always get this runtime error, when testing on a real device. Does not happen on simulator.
Thread 1: EXC_BAD_ACCESS (code=1, address=0x48)
PLEASE: Before you mark that question as “duplicate”, consider that this must have something to do with the release of iOS13, because before it didn’t happen and the code is just "usual".
Here is my code, also on gitHub.
I have a property in my ViewController to prevent ARC deallocating my AVAudioPlayer:
private var mySoundPlayer: AVAudioPlayer = AVAudioPlayer()
I have a routine, where the “play sound” should be performed (here happens the error, when assigning a new instance of AVAudioPlayer. The resourceURL is not the problem, the RE-ASSIGNING is the problem, I tested it with a new instance not being assigned and i did not crash.
// -------------------------------------------------
// MARK: Private Methods
// -------------------------------------------------
private func makeSoundEvent(_ soundEvent : SoundEvent) {
guard Settings().getSound() == .soundON else { return }
guard let urlToRessource : URL = soundEvent.getFileURLToSoundRessource() else { return }
do {
mySoundPlayer = try AVAudioPlayer(contentsOf: urlToRessource)
try? AVAudioSession.sharedInstance().setActive(true)
mySoundPlayer.play()
}
catch { print("Could not create AVPlayer for ressource \(urlToRessource)") }
}
And here I have the call of that subroutine, somewhere in my viewDidLoad() with a delay of 2 seconds.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.makeSoundEvent(.startFanfare)
}
I think it somehow does not work because of the async thread. But since it is on the main thread, I thought this should work.
Just remove the initialisation and it will work
private var mySoundPlayer: AVAudioPlayer!
Cheers!!!
private var mySoundPlayer: AVAudioPlayer = AVAudioPlayer()
AVAudioPlayer doesn't have init() listed as a valid initializer. The reference page shows four separate initializers, all of which take at least one parameter. If you were using the line above in code prior to iOS 13.1 without crashing, you were initializing the audio player incorrectly and probably just getting lucky that it wasn't a problem.
I don't know what changed specifically with AVAudioPlayer in iOS 13.1, but the release notes show quite a few audio-related changes, and it seems likely that some change to that class introduced a dependency on something that happens at initialization time.
I get random crashes (which I can't reproduce on devices I own) in my app with exception:
Cannot remove an observer Foundation.NSKeyValueObservation 0xaddress for the key path "readyForDisplay" from AVPlayerLayer 0xaddress because it is not registered as an observer.
This happens when I deallocate a UIView which contains AVPlayerLayer.
My init:
private var playerLayer : AVPlayerLayer { return self.layer as! AVPlayerLayer }
init(withURL url : URL) {
...
self.asset = AVURLAsset(url: url)
self.playerItem = AVPlayerItem(asset: self.asset)
self.avPlayer = AVPlayer(playerItem: self.playerItem)
super.init(frame: .zero)
...
let avPlayerLayerIsReadyForDisplayObs = self.playerLayer.observe(\AVPlayerLayer.isReadyForDisplay, options: [.new]) { [weak self] (plLayer, change) in ... }
self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]
...
}
My deinit where exception is thrown:
deinit {
self.kvoPlayerObservers.forEach { $0.invalidate() }
...
NotificationCenter.default.removeObserver(self)
}
According to Crashlytics it happens on iOS 11.4.1 on different iPhones.
The code leading to deinit is pretty simple:
// Some UIViewController context.
self.viewWithAVLayer?.removeFromSuperview()
self.viewWithAVLayer = nil
I would appreciate any thoughts on why this happens.
I have seen this bug but it doesn't seem to be the cause for me.
EDIT 1:
Additional info for posterity. On iOS 10 if I don't invalidate I get reproducible crash on deinit. On iOS 11 it works without invalidation (not checked yet if crash disappears if I don't invalidate and let observers to be deinited with my class).
EDIT 2:
Additional info for posterity: I have also found this Swift bug which might be related - SR-6795.
After
self.kvoPlayerObservers.forEach { $0.invalidate() }
Add
self.kvoPlayerObservers.removeAll()
Also I don’t like this line:
self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]
kvoPlayerObservers should be a Set and you should insert observers one by one as you receive them.
I have accepted matt's answer but I want to provide more info on how I actually tackled my problem.
My deinit that doesn't crash looks like this:
if let exception = tryBlock({ // tryBlock is Obj-C exception catcher.
self.kvoPlayerObservers.forEach { $0.invalidate() };
self.kvoPlayerObservers.removeAll()
}) {
remoteLoggingSolution.write(exception.description)
}
... // do other unrelated stuff
Basically I try to catch Obj-C exception if it occurs and try to log it remotely.
I have this code in production for past 2 weeks and since then I didn't receive neither crashes nor exception logs so I assume matt's proposal to add kvoPlayerObservers.removeAll() was correct (at least for my particular case).