I have a crash report (it is already symbolicated at least I would hope so as I obtained this log from XCode Organizer)
Incident Identifier: F4324555-0916-4E32-82EF-3272917367BB
Beta Identifier: 80811904-A512-48A1-9593-D386703A62F0
Hardware Model: iPhone7,2
Process: SelfieSuperStarz [596]
Path: /private/var/containers/Bundle/Application/BFA0D82B-274B-400B-8F84-52A1D7369C51/SelfieSuperStarz.app/SelfieSuperStarz
Identifier: com.PuckerUp.PuckerUp
Version: 21 (1.31)
Beta: YES
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: com.PuckerUp.PuckerUp [434]
Date/Time: 2017-07-29 20:06:11.7394 -0400
Launch Time: 2017-07-29 19:34:39.7433 -0400
OS Version: iPhone OS 10.3.2 (14F89)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x18bebafe0 __exceptionPreprocess + 124 (NSException.m:165)
1 libobjc.A.dylib 0x18a91c538 objc_exception_throw + 56 (objc-exception.mm:521)
2 CoreFoundation 0x18be26eb4 -[__NSArray0 objectAtIndex:] + 108 (CFArray.c:69)
3 SelfieSuperStarz 0x10007b708 specialized _ArrayBuffer._getElementSlowPath(Int) -> AnyObject + 116
4 SelfieSuperStarz 0x10007ea40 specialized Merger.merge(completion : () -> (), assets : [Asset]) -> () + 1444 (Merger.swift:0)
5 SelfieSuperStarz 0x100071f3c specialized AssetView.finish(UIButton) -> () + 520 (Merger.swift:0)
6 SelfieSuperStarz 0x1000712d0 #objc AssetView.finish(UIButton) -> () + 40 (AssetView.swift:0)
7 UIKit 0x192021010 -[UIApplication sendAction:to:from:forEvent:] + 96 (UIApplication.m:4580)
8 UIKit 0x192020f90 -[UIControl sendAction:to:forEvent:] + 80 (UIControl.m:609)
9 UIKit 0x19200b504 -[UIControl _sendActionsForEvents:withEvent:] + 440 (UIControl.m:694)
10 UIKit 0x192020874 -[UIControl touchesEnded:withEvent:] + 576 (UIControl.m:446)
11 UIKit 0x192020390 -[UIWindow _sendTouchesForEvent:] + 2480 (UIWindow.m:2122)
12 UIKit 0x19201b728 -[UIWindow sendEvent:] + 3192 (UIWindow.m:2292)
13 UIKit 0x191fec33c -[UIApplication sendEvent:] + 340 (UIApplication.m:10778)
14 UIKit 0x1927e6014 __dispatchPreprocessedEventFromEventQueue + 2400 (UIEventDispatcher.m:1448)
15 UIKit 0x1927e0770 __handleEventQueue + 4268 (UIEventDispatcher.m:1671)
16 UIKit 0x1927e0b9c __handleHIDEventFetcherDrain + 148 (UIEventDispatcher.m:1706)
17 CoreFoundation 0x18be6942c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 (CFRunLoop.c:1943)
18 CoreFoundation 0x18be68d9c __CFRunLoopDoSources0 + 540 (CFRunLoop.c:1989)
19 CoreFoundation 0x18be669a8 __CFRunLoopRun + 744 (CFRunLoop.c:2821)
20 CoreFoundation 0x18bd96da4 CFRunLoopRunSpecific + 424 (CFRunLoop.c:3113)
21 GraphicsServices 0x18d800074 GSEventRunModal + 100 (GSEvent.c:2245)
22 UIKit 0x192051058 UIApplicationMain + 208 (UIApplication.m:4089)
23 SelfieSuperStarz 0x10002e990 main + 56 (AppDelegate.swift:16)
24 libdyld.dylib 0x18ada559c start + 4
As you can see it says in my Class Merger at line 0. Which is impossible, as you can probably assume. I am not sure how to interpret what specialized means or why the #objc is there.
3 SelfieSuperStarz 0x10007b708 specialized _ArrayBuffer._getElementSlowPath(Int) -> AnyObject + 116
4 SelfieSuperStarz 0x10007ea40 specialized Merger.merge(completion : () -> (), assets : [Asset]) -> () + 1444 (Merger.swift:0)
5 SelfieSuperStarz 0x100071f3c specialized AssetView.finish(UIButton) -> () + 520 (Merger.swift:0)
6 SelfieSuperStarz 0x1000712d0 #objc AssetView.finish(UIButton) -> () + 40 (AssetView.swift:0)
Just not sure where the error is occurring as the line says Merger:0 and I'm not sure what those headers (specialized/objc) mean if they are telling me anything.
Here is my merge function inside Merger. I use a variety of loops and calculations for opacity and determine things, but I check for nil in locations.
func merge(completion:#escaping () -> Void, assets:[Asset]) {
self.setupAI()
let assets = assets.sorted(by: { $0.layer.zPosition < $1.layer.zPosition })
if let firstAsset = controller.firstAsset {
let mixComposition = AVMutableComposition()
let firstTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo,
preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, self.controller.realDuration),
of: firstAsset.tracks(withMediaType: AVMediaTypeVideo)[0],
at: kCMTimeZero)
} catch _ {
print("Failed to load first track")
}
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
var myTracks:[AVMutableCompositionTrack] = []
var ranges:[ClosedRange<CMTime>] = []
for asset in assets {
let secondTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo,
preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
secondTrack.preferredTransform = asset.asset.preferredTransform
do {
try secondTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, asset.endTime-asset.beginTime),
of: asset.asset.tracks(withMediaType: AVMediaTypeVideo)[0],
at: CMTime(seconds: CMTimeGetSeconds(asset.beginTime), preferredTimescale: 600000))
} catch _ {
print("Failed to load second track")
}
if(ranges.count == 0) {
ranges.append(asset.beginTime...asset.endTime)
}
else {
var none = true
for range in ranges {
let start = range.contains(asset.beginTime)
let end = range.contains(asset.endTime)
var connection = false
var nothing = false
//This range is completely encompassed (begin and end inside)
if(start && end) {
//Don't add to the rnge
none = false
nothing = true
}
//Begin is in range (right side)
else if(start && !end) {
connection = true
none = false
}
//End is in range (left side)
else if(!start && end) {
connection = true
none = false
}
var connected = false
//It connects 2 different timess
if(connection) {
for range2 in ranges {
if(range != range2) {
if(start && range2.contains(asset.endTime)) {
let index = ranges.index(of: range)
if(index != nil) {
ranges.remove(at: index!)
ranges.append(range.lowerBound...range2.upperBound)
connected = true
break
}
}
else if(end && range2.contains(asset.beginTime)) {
let index = ranges.index(of: range)
if(index != nil) {
ranges.remove(at: index!)
ranges.append(range.lowerBound...range2.upperBound)
connected = true
break
}
}
}
}
}
if(!connected && !none && !nothing) {
if(start) {
let index = ranges.index(of: range)
if(index != nil) {
ranges.remove(at: index!)
ranges.append(range.lowerBound...asset.endTime)
}
}
else if(end) {
let index = ranges.index(of: range)
if(index != nil) {
ranges.remove(at: index!)
ranges.append(asset.beginTime...asset.endTime)
}
}
}
}
if(none) {
ranges.append(asset.beginTime...asset.endTime)
}
}
myTracks.append(secondTrack)
}
for range in ranges {
print(CMTimeGetSeconds(range.lowerBound), CMTimeGetSeconds(range.upperBound))
}
for assets in self.controller.assets {
print(CMTimeGetSeconds(assets.beginTime), CMTimeGetSeconds(assets.endTime))
}
if let loadedAudioAsset = self.controller.audioAsset {
let audioTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: 0)
do {
try audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, self.controller.realDuration),
of: loadedAudioAsset.tracks(withMediaType: AVMediaTypeAudio)[0] ,
at: kCMTimeZero)
} catch _ {
print("Failed to load Audio track")
}
}
let mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, self.controller.realDuration)
// 2.2
let firstInstruction = self.videoCompositionInstructionForTrack(firstTrack, firstAsset)
var instructions:[AVMutableVideoCompositionLayerInstruction] = []
var counter:Int = 0
for tracks in myTracks {
let secondInstruction = self.videoCompositionInstructionForTrack(tracks, assets[counter].asset, type:true)
let index = myTracks.index(of: tracks)
//This should never be nil, but if it is, it might cause opacity's to go out of whack for that specific track. Only reason I can think of why I am crashing in this method.
if(index != nil) {
if(index! < assets.count-1) {
for i in (counter+1...assets.count-1) {
if(assets[counter].endTime > assets[i].endTime) {
secondInstruction.setOpacity(1.0, at: assets[i].endTime)
secondInstruction.setOpacity(0.0, at: assets[counter].endTime)
print("Bigger")
break
}
}
}
if(index! > 0) {
for i in (0...counter).reversed() {
if(assets[counter].endTime < assets[i].endTime) {
secondInstruction.setOpacity(0.0, at: assets[counter].endTime)
print("Smaller")
break
}
}
}
if(counter < myTracks.count-1) {
if(assets[counter].layer.zPosition <= assets[counter+1].layer.zPosition) {
secondInstruction.setOpacity(0.0, at: assets[counter+1].beginTime)
}
else {
secondInstruction.setOpacity(0.0, at: assets[counter].endTime)
}
}
instructions.append(secondInstruction)
counter += 1
}
}
for range in ranges {
firstInstruction.setOpacity(0.0, at: range.lowerBound)
firstInstruction.setOpacity(1.0, at: range.upperBound)
}
// 2.3
mainInstruction.layerInstructions = [firstInstruction] + instructions
let imageLayer = CALayer()
let image = UIImage(named: "Watermark")
imageLayer.contents = image!.cgImage
let ratio = (firstAsset.tracks(withMediaType: AVMediaTypeVideo)[0].naturalSize.width/image!.size.width)/2
let rect = CGRect(x: image!.size.width*ratio, y: 0, width: image!.size.width*ratio, height: image!.size.height*ratio)
imageLayer.frame = rect
imageLayer.backgroundColor = UIColor.clear.cgColor
imageLayer.opacity = 0.75
let videoLayer = CALayer()
videoLayer.frame = CGRect(x: 0, y: 0, width: firstAsset.tracks(withMediaType: AVMediaTypeVideo)[0].naturalSize.width, height: firstAsset.tracks(withMediaType: AVMediaTypeVideo)[0].naturalSize.height)
let parentlayer = CALayer()
parentlayer.frame = CGRect(x: 0, y: 0, width: image!.size.width*ratio, height: image!.size.height*ratio)
parentlayer.addSublayer(videoLayer)
parentlayer.addSublayer(imageLayer)
let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [mainInstruction]
mainComposition.frameDuration = CMTimeMake(1, 30)
mainComposition.renderSize = self.controller.firstAsset!.tracks(withMediaType: AVMediaTypeVideo)[0].naturalSize
mainComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentlayer)
It's quite clear that the method "Merger.merge" accesses a non-existing element. The debugger will show you where that is.
I'd guess that some thread is modifying some array behind your back so that an index that was valid at some point becomes invalid. And "for range2 in ranges" when you later on modify "ranges" is asking for trouble.
I am guessing that the problem is caused by line 129, considering the +1444 offset and array access. Have you tried a video without audio, like a video taken without an audio permission? I encountered an out of bound crash by assuming videos taken in my app always had audio tracks. You will be surprised by users what video they feed into your app. I even had a user crashing my app with a flv video, selected from their phone album.
(I am not sure if this will work for Swift)
It is also possible to locate the line in Xcode using the debugger. First, you run the app with the same optimzation setting as the release build. Then you break different lines in the function to check the assembly code.
How to see assembly code in xcode 6. You might need to scroll to the top to double check the function name and the meaning of the offset.
_ArrayBuffer._getElementSlowPath is a class in the private API, indicated by the underscore prefix. You will probably not find any credible and/or official sources about it.
The incompleteness in your crash log is probably caused by bugs/immaturity of Swift (the tools behind it). Welcome to one of the most trended and hyped language. Even in working conditions, Swift gives line 0 for generated code where the code does not correspond to any meaningful parts of the source code. It is not your case though.
Related
When I try to fetch user data from Firebase a crash occurs for some users, I can't reproduce this crash myself but I do have the following crash log:
0 Ski Tracker 0x77bf0 closure #1 in HistoryPresenter.downloadHistory(completionHandler:) + 4340857840 (HistoryPresenter.swift:4340857840)
1 Ski Tracker 0x86c8 closure #1 in FetchFromDatabase.fetchUserHistoryFromDatabase(uid:completionHandler:) + 4340401864 (<compiler-generated>:4340401864)
2 Ski Tracker 0x8604 thunk for #escaping #callee_guaranteed (#guaranteed FIRDataSnapshot) -> () + 4340401668 (<compiler-generated>:4340401668)
3 FirebaseDatabase 0x1df28 __92-[FIRDatabaseQuery observeSingleEventOfType:andPreviousSiblingKeyWithBlock:withCancelBlock:]_block_invoke + 120
4 FirebaseDatabase 0xbf94 __43-[FChildEventRegistration fireEvent:queue:]_block_invoke.11 + 80
5 libdispatch.dylib 0x24b4 _dispatch_call_block_and_release + 32
6 libdispatch.dylib 0x3fdc _dispatch_client_callout + 20
7 libdispatch.dylib 0x127f4 _dispatch_main_queue_drain + 928
8 libdispatch.dylib 0x12444 _dispatch_main_queue_callback_4CF + 44
9 CoreFoundation 0x9a6f8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
10 CoreFoundation 0x7c058 __CFRunLoopRun + 2036
11 CoreFoundation 0x80ed4 CFRunLoopRunSpecific + 612
12 GraphicsServices 0x1368 GSEventRunModal + 164
13 UIKitCore 0x3a23d0 -[UIApplication _run] + 888
14 UIKitCore 0x3a2034 UIApplicationMain + 340
15 libswiftUIKit.dylib 0x35308 UIApplicationMain(_:_:_:_:) + 104
16 Ski Tracker 0x7160 main + 4340396384 (FriendView.swift:4340396384)
17 ??? 0x1f6938960 (Missing)
If I understand the crash log correctly the code which is causing the crash is within the fetchUserHistoryFromDatabase function:
func fetchUserHistoryFromDatabase(uid : String, completionHandler: #escaping([String : Any]?) -> Void ) {
ref?.child("users").child(uid).child("runData").observeSingleEvent(of: .value, with: { snapshot in
guard let result = snapshot.value as? [String:Any] else {
print("Error no rundata")
completionHandler(nil)
return
}
completionHandler(result)
})
}
This function is called from downloadHistory where potential nil values are handled:
private func downloadHistory(completionHandler: #escaping () -> Void) {
if let id = Auth.auth().currentUser?.uid {
FetchFromDatabase().fetchUserHistoryFromDatabase(uid : id, completionHandler: { [weak self] dict in
if dict != nil {
for run in dict! {
self?.determineTimeStamp(run : run)
}
if !(self!.tempDict.isEmpty) {
let sortedDict = self?.tempDict.keys.sorted(by: { $0 > $1 } )
self?.convertDictToArray(sortedDict: sortedDict!)
}
}
completionHandler()
}
)}
}
Any help here is greatly appreciated.
Remove the force unwrapping from your code. Every ! is an invitation for a crash.
private func downloadHistory(completionHandler: #escaping () -> Void) {
if let id = Auth.auth().currentUser?.uid {
FetchFromDatabase().fetchUserHistoryFromDatabase(uid : id, completionHandler: { [weak self] dict in
guard let self = self else {
completion()
return
}
if let dict = dict {
for run in dict {
self.determineTimeStamp(run : run)
}
if !self.tempDict.isEmpty {
let sortedDict = self.tempDict.keys.sorted(by: { $0 > $1 } )
self.convertDictToArray(sortedDict: sortedDict)
}
}
completionHandler()
}
)}
}
I notice a self! there dangerous, because a user could leave the calling context of the function and since the closure has a capture list of weak self, it should return nil but you are forcing it
try this
private func downloadHistory(completionHandler: #escaping () -> Void) {
if let id = Auth.auth().currentUser?.uid {
FetchFromDatabase().fetchUserHistoryFromDatabase(uid : id, completionHandler: { [weak self] dict in
guard let self = self else { completionHandler()
return }
if let safeDict = dict {
for run in dict {
self.determineTimeStamp(run : run)
}
if (self.tempDict.isEmpty) {
let sortedDict = self.tempDict.keys.sorted(by: { $0 > $1 } )
self.convertDictToArray(sortedDict: sortedDict)
}
}
completionHandler()
}
)}
}
Crashes are reported into firebase console. Can anyone help me. i am sending data to server using Socket.
Here is crash description:
Crashed: com.apple.main-thread
0 AppName 0x10ef40 partial apply for closure #2 in sendDataRecursively() + 4329697088 (swift:4329697088)
1 AppName 0x23824 thunk for #escaping #callee_guaranteed () -> () + 4328732708 (<compiler-generated>:4328732708)
2 libdispatch.dylib 0x1e68 _dispatch_call_block_and_release + 32
3 libdispatch.dylib 0x3a2c _dispatch_client_callout + 20
4 libdispatch.dylib 0x11f48 _dispatch_main_queue_drain + 928
5 libdispatch.dylib 0x11b98 _dispatch_main_queue_callback_4CF + 44
6 CoreFoundation 0x522f0
CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
7 CoreFoundation 0xc1f4 __CFRunLoopRun + 2532
8 CoreFoundation 0x1f6b8 CFRunLoopRunSpecific + 600
9 GraphicsServices 0x1374 GSEventRunModal + 164
10 UIKitCore 0x513e88 -[UIApplication _run] + 1100
11 UIKitCore 0x2955ec UIApplicationMain + 364
12 AppName 0x48dac main + 17 (AppDelegate.swift:17)
13 ??? 0x1008edce4 (Missing)
Here is my function:
#objc func sendDataRecursively() {
let reachability = try! Reachability()
if reachability.connection != .unavailable {
DispatchQueue.global(qos: .userInitiated).async { //previous .bakground
if self.msgCnt == 127 {
self.msgCnt = 0
}
self.msgCnt += 1
self.sendRequest()
}
} else {
DispatchQueue.main.async {
self.previousStatusWhenDisconnect = self.motionDetectionLbl?.text ?? ""
self.appDelegate.statusLbl?.text = String(format: "%# %#", (self.appDelegate.statusLbl?.text)!, StartVCStringsEnglish.disConnectedString)
}
self.networkTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.checkNetworkRecursively), userInfo: nil, repeats: true)
}
}
Here is the my other function. i am sending data to my Socket function. i did't got the crash but its reported into firebase. Also in firebase has not much more information about the crash. its just show the function name only.
private func sendRequest() {
self.calculateMessageData()
var requestData: Data?
var txData = [UInt8()]
var crc: Int
if self.msgID == Int8(EnMessageType.basicSafetyMessage.rawValue) {
requestData = self.getBasicSafetyMessage()
} else {
requestData = self.getPersonalSafetyMessage()
}
crc = computeCRC(data: requestData!, length: requestData!.count)
// wrap data in 7E, do byte stuffing and add CRC
txData = []
txData.append(0x7E)
for ii in 0..<requestData!.count {
switch requestData![ii] {
case 0x7D:
txData.append(0x7D)
txData.append(0x5D)
break
case 0x7E:
txData.append(0x7D)
txData.append(0x5E)
break
default:
txData.append(requestData![ii])
break
}
}
txData.append((UInt8)(crc >> 8))
txData.append((UInt8)(crc & 0xFF))
txData.append(0x7E)
requestData = (Data)(txData)
if AppSingletonVariable.sharedInstance.isConnected == true { AppSingletonVariable.sharedInstance.mySocket.sendDataToServer(reqData: requestData!)
}
}
Thanks,
You can see from the crash description that there is issue in 2nd closure in sendDataRecursively() function:
DispatchQueue.main.async {
self.previousStatusWhenDisconnect = self.motionDetectionLbl?.text ?? ""
self.appDelegate.statusLbl?.text = String(format: "%# %#", (self.appDelegate.statusLbl?.text)!, StartVCStringsEnglish.disConnectedString)
}
self.networkTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.checkNetworkRecursively), userInfo: nil, repeats: true)
The issue is probably '!' in this expression:
(self.appDelegate.statusLbl?.text)!
If statusLbl is nil, this code crashes. As it was mentioned in comment, it's not safe to force unwrap optionals and this is the reason.
Replace your closure with this:
DispatchQueue.main.async {
self.previousStatusWhenDisconnect = self.motionDetectionLbl?.text ?? ""
if let text = self.appDelegate.statusLbl?.text {
self.appDelegate.statusLbl?.text = String(format: "%# %#", text, StartVCStringsEnglish.disConnectedString)
}
}
self.networkTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.checkNetworkRecursively), userInfo: nil, repeats: true)
I am trying to implement a table view that displays books information in every cell. I get this information from the API. Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var allBooksTable: UITableView!
var bookList:myList? = nil {
didSet {
allBooksTable.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.allBooksTable.dataSource = self
self.allBooksTable.delegate = self
let url = URL(string: "https://ipvefa0rg0.execute-api.us-east-1.amazonaws.com/dev/books?lang=fr&term=self")!
var request = URLRequest(url: url)
request.setValue(
"jFXzWHx7SkK6",
forHTTPHeaderField: "api-key"
)
request.httpMethod = "GET"
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
} else if let data = data {
do {
let decodedData = try JSONDecoder().decode(myList.self,
from: data)
self.bookList = decodedData
print("user: ", decodedData.list[0].imageLinks.thumbnail)
print("===================================")
} catch let DecodingError.dataCorrupted(context) {
print(context)
} catch let DecodingError.keyNotFound(key, context) {
print("Key '\(key)' not found:", context.debugDescription)
//print("codingPath:", context.codingPath)
} catch let DecodingError.valueNotFound(value, context) {
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch let DecodingError.typeMismatch(type, context) {
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch {
print("error: ", error)
}
} else {
// Handle unexpected error
}
}
task.resume()
}
}
extension ViewController: UITableViewDataSource , UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as! bookTableViewCell
cell.bookName.text = bookList?.list[indexPath.row].title
if bookList?.list[indexPath.row].imageLinks.smallThumbnail != nil{
//cell.img.load(url: (bookList?.list[indexPath.row].imageLinks.smallThumbnail)!)
print((bookList?.list[indexPath.row].imageLinks.smallThumbnail)!)
cell.img.downloaded(from: (bookList?.list[indexPath.row].imageLinks.smallThumbnail)!)
}
return cell
}
}
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
When I run the app, it only shows my the first book and then crashes with the following error.
2020-10-15 23:12:00.953424+1100 MSA[50129:2517792] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff2043a126 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177f78 objc_exception_throw + 48
2 CoreAutoLayout 0x00007fff58010d41 -[NSISEngine tryToOptimizeReturningMutuallyExclusiveConstraints] + 0
3 CoreAutoLayout 0x00007fff58010fcd -[NSISEngine withBehaviors:performModifications:] + 25
4 UIKitCore 0x00007fff24ac64ad -[UIView(AdditionalLayoutSupport) _recursiveUpdateConstraintsIfNeededCollectingViews:forSecondPass:] + 112
5 UIKitCore 0x00007fff24ac6136 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 827
6 UIKitCore 0x00007fff24ac6a08 __100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_block_invoke + 85
7 UIKitCore 0x00007fff24ac6594 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:] + 154
8 UIKitCore 0x00007fff24ac7482 -[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeededWithViewForVariableChangeNotifications:] + 393
9 UIKitCore 0x00007fff24ba9ad6 -[UIView _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] + 275
10 UIKitCore 0x00007fff24bbda37 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2979
11 QuartzCore 0x00007fff27a3dd87 -[CALayer layoutSublayers] + 258
12 QuartzCore 0x00007fff27a44239 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
13 UIKitCore 0x00007fff24ba8fe9 -[UIView(Hierarchy) layoutBelowIfNeeded] + 573
14 UIKitCore 0x00007fff24bb0479 +[UIView(Animation) performWithoutAnimation:] + 84
15 UIKitCore 0x00007fff248954d0 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 1300
16 UIKitCore 0x00007fff2485e8bb -[UITableView _updateVisibleCellsNow:] + 2942
17 UIKitCore 0x00007fff2487e6e6 -[UITableView layoutSubviews] + 237
18 UIKitCore 0x00007fff24bbd9ce -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2874
19 QuartzCore 0x00007fff27a3dd87 -[CALayer layoutSublayers] + 258
20 QuartzCore 0x00007fff27a44239 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
21 QuartzCore 0x00007fff27a4ff91 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
22 QuartzCore 0x00007fff27990078 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
23 QuartzCore 0x00007fff279c6e13 _ZN2CA11Transaction6commitEv + 783
24 QuartzCore 0x00007fff279c7616 _ZN2CA11Transaction14release_threadEPv + 210
25 libsystem_pthread.dylib 0x00007fff5dcda054 _pthread_tsd_cleanup + 551
26 libsystem_pthread.dylib 0x00007fff5dcdc512 _pthread_exit + 70
27 libsystem_pthread.dylib 0x00007fff5dcd9ddd _pthread_wqthread_exit + 77
28 libsystem_pthread.dylib 0x00007fff5dcd8afc _pthread_wqthread + 481
29 libsystem_pthread.dylib 0x00007fff5dcd7b77 start_wqthread + 15
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Could you please help me to understand what's going on here? I have looked over for similar threads, but most of the solutions are specific to the question.
if a UIElement getting update in background thread thats why applications getting crashed so whenever you want to update UI you need to update that UI Element in main thread, and your session data task is running in background thread and there you set the value bookList but when bookList is set there is an property observer which is reload the tableview in background thread so there is two solutions.
inside your api calling functions you need to set the property in main thread like this:-
DispatchQueue.main.async {
self.bookList = decodedData
}
inside your property observer you need to do like that
var bookList:myList? = nil {
didSet {
DispatchQueue.main.async {
allBooksTable.reloadData()
}
}
}
Enjoy:-
The issue is that you set bookList from a background thread (since URLSession.dataTask calls its completion on a background thread) and in the didSet of bookList, you update the UI. You should dispatch the UI update to the main thread.
var bookList:myList? = nil {
didSet {
DispatchQueue.main.async {
allBooksTable.reloadData()
}
}
}
You can set the bookList on main thread like below...
DispatchQueue.main.async {
self.bookList = decodedData
}
I'm trying to create an app that:
Records my microphone and saves the output to a file
Plays the last recorded file
The playback should be manipulated with effects such as pitch-shift
So far I've got 1+2 down, but when I try to assign the AudioKit.output to my timePitch (or PitchShifter for that matter), I get an exception (see below). Can anyone help me out? Seems like if I set output to anything else than player, it crashes..
Disclaimer: I'm new to Swift, so please go easy on me and forgive my bad code
2017-11-08 16:39:58.637075+0100 mysoundplayer[41113:759865] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'player started when in a disconnected state'
*** First throw call stack:
(
0 CoreFoundation 0x0000000108a3c1ab __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00000001047ddf41 objc_exception_throw + 48
2 CoreFoundation 0x0000000108a41372 +[NSException raise:format:arguments:] + 98
3 AVFAudio 0x000000010b3bb00e _Z19AVAE_RaiseExceptionP8NSStringz + 158
4 AVFAudio 0x000000010b4131ce _ZN21AVAudioPlayerNodeImpl9StartImplEP11AVAudioTime + 204
5 AVFAudio 0x000000010b412482 -[AVAudioPlayerNode playAtTime:] + 82
6 AudioKit 0x0000000103a2270d _T08AudioKit13AKAudioPlayerC4playySo11AVAudioTimeCSg2at_tFTf4gn_n + 1933
7 AudioKit 0x0000000103a1c78d _T08AudioKit13AKAudioPlayerC5startyyF + 45
8 mysoundplayer 0x00000001035dd3b8 _T010mysoundplayer14ViewControllerC14playLoadedFileyyF + 1832
9 mysoundplayer 0x00000001035dca1e _T010mysoundplayer14ViewControllerC4playySo8UIButtonCF + 46
10 mysoundplayer 0x00000001035dca6c _T010mysoundplayer14ViewControllerC4playySo8UIButtonCFTo + 60
11 UIKit 0x000000010507c275 -[UIApplication sendAction:to:from:forEvent:] + 83
12 UIKit 0x00000001051f94a2 -[UIControl sendAction:to:forEvent:] + 67
13 UIKit 0x00000001051f97bf -[UIControl _sendActionsForEvents:withEvent:] + 450
14 UIKit 0x00000001051f81e7 -[UIControl touchesBegan:withEvent:] + 282
15 UIKit 0x00000001050f1916 -[UIWindow _sendTouchesForEvent:] + 2130
16 UIKit 0x00000001050f32de -[UIWindow sendEvent:] + 4124
17 UIKit 0x0000000105096e36 -[UIApplication sendEvent:] + 352
18 UIKit 0x00000001059d9434 __dispatchPreprocessedEventFromEventQueue + 2809
19 UIKit 0x00000001059dc089 __handleEventQueueInternal + 5957
20 CoreFoundation 0x00000001089df231 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
21 CoreFoundation 0x0000000108a7ee41 __CFRunLoopDoSource0 + 81
22 CoreFoundation 0x00000001089c3b49 __CFRunLoopDoSources0 + 185
23 CoreFoundation 0x00000001089c312f __CFRunLoopRun + 1279
24 CoreFoundation 0x00000001089c29b9 CFRunLoopRunSpecific + 409
25 GraphicsServices 0x000000010cc289c6 GSEventRunModal + 62
26 UIKit 0x000000010507a5e8 UIApplicationMain + 159
27 mysoundplayer 0x00000001035e12a7 main + 55
28 libdyld.dylib 0x000000010aa49d81 start + 1
29 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Source code:
import AudioKit
import AudioKitUI
import UIKit
class ViewController: UIViewController {
var micMixer: AKMixer!
var recorder: AKNodeRecorder!
var player: AKAudioPlayer!
var tape: AKAudioFile!
var timePitch: AKTimePitch!
var pitchShifter: AKPitchShifter!
var mainMixer : AKMixer!
var loadedFile: AKAudioFile!
let mic = AKMicrophone()
var state = State.readyToRecord
enum State {
case readyToRecord
case recording
case readyToPlay
case playing
}
#IBAction func toggleRecord(_ sender: UIButton) {
switch state {
case .recording:
sender.setTitle("record", for: .normal)
state = .readyToRecord
do {
try player.reloadFile()
} catch {
print("Error reloading!")
}
let recordedDuration = player != nil ? player.audioFile.duration : 0
if recordedDuration > 0.0 {
recorder.stop()
let randomfilename:String = NSUUID().uuidString + ".m4a"
print("Filename: \(randomfilename)")
player.audioFile.exportAsynchronously(name: randomfilename, baseDir: .documents, exportFormat: .m4a, callback: {file, exportError in
if let error = exportError {
print("Export failed \(error)")
} else {
print("Export succeeded")
self.loadedFile = file
}
})
}
case .readyToRecord:
do {
try recorder.record()
sender.setTitle("stop", for: .normal)
state = .recording
} catch { print("Error recording!") }
default:
print("no")
}
}
#IBAction func play(_ sender: UIButton) {
playLoadedFile()
}
#IBAction func valueChanged(_ sender: UISlider) {
timePitch.pitch = Double(sender.value)
}
func playLoadedFile() {
do {
try player.replace(file: loadedFile)
player.start()
} catch { print("Error playing!") }
}
func exportedAudioFile(filename: String) {
print("yay")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
AKAudioFile.cleanTempDirectory()
AKSettings.bufferLength = .medium
AKSettings.defaultToSpeaker = true
//inputPlot.node = mic
micMixer = AKMixer(mic)
mainMixer = AKMixer(player,timePitch)
pitchShifter = AKPitchShifter(player)
timePitch = AKTimePitch(player)
recorder = try? AKNodeRecorder(node: micMixer)
if let file = recorder.audioFile {
player = try? AKAudioPlayer(file: file)
}
AudioKit.output = timePitch // works with player
AudioKit.start()
print("mainMixer status: \(mainMixer.isStarted)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
It looks like mainMixer isn't connected to anything. Try changing AudioKit.output = timePitch to AudioKit.output = mainMixer.
As for best practices, get rid of any try?s. Use a do try catch and at least print the error.
if let file = recorder.audioFile {
do{
player = try AKAudioPlayer(file: file)
} catch {
print(error)
}
}
You’re attaching the player to the mixer before you create it. At the time where you give player to AKMixer(), it is nil. Move the mixer creation after the player assignment.
Since we have renamed (Bestemming -> Place) the class and rewrote it from Objective-c to Swift some users experience crashes with it. We are trying to load an object from the NSUserDefaults with the NSCoding principle.
The crash:
Thread : Crashed: com.apple.main-thread
0 Flitsmeister 0x10018b720 specialized Place.init(coder : NSCoder) -> Place? (Place.swift)
1 Flitsmeister 0x10018a6f4 #objc Place.init(coder : NSCoder) -> Place? (Place.swift)
2 Foundation 0x1839ab92c _decodeObjectBinary + 2276
3 Foundation 0x1839aaf90 _decodeObject + 304
4 Foundation 0x1839aa124 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 92
5 Flitsmeister 0x100103fa0 +[SharedUserDefaultsManager WorkPlace] (SharedUserDefaultsManager.m:72)
6 Flitsmeister 0x100090830 -[InvoerBestemmingTableViewController viewWillAppear:] (InvoerBestemmingTableViewController.m:106)
7 UIKit 0x187d8074c -[UIViewController _setViewAppearState:isAnimating:] + 628
8 UIKit 0x187d804c0 -[UIViewController __viewWillAppear:] + 156
9 UIKit 0x187e27130 -[UINavigationController _startTransition:fromViewController:toViewController:] + 760
10 UIKit 0x187e26a6c -[UINavigationController _startDeferredTransitionIfNeeded:] + 868
11 UIKit 0x187e26694 -[UINavigationController __viewWillLayoutSubviews] + 60
12 UIKit 0x187e265fc -[UILayoutContainerView layoutSubviews] + 208
13 UIKit 0x187d63778 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 656
14 QuartzCore 0x185772b2c -[CALayer layoutSublayers] + 148
15 QuartzCore 0x18576d738 CA::Layer::layout_if_needed(CA::Transaction*) + 292
16 QuartzCore 0x18576d5f8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32
17 QuartzCore 0x18576cc94 CA::Context::commit_transaction(CA::Transaction*) + 252
18 QuartzCore 0x18576c9dc CA::Transaction::commit() + 512
19 UIKit 0x187d59c78 _afterCACommitHandler + 180
20 CoreFoundation 0x18302c588 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
21 CoreFoundation 0x18302a32c __CFRunLoopDoObservers + 372
The class:
#objc(Place)
class Place : NSObject, NSCoding, CustomDebugStringConvertible
{
let name: String
let location: CLLocation
var lastUsed: NSDate?
var type: PlaceType
var address: String?
//MARK: - NSCoding protocol
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey: "name")
aCoder.encodeObject(address, forKey: "address")
aCoder.encodeInt(type.rawValue, forKey: "type")
aCoder.encodeObject(location, forKey: "location")
aCoder.encodeObject(lastUsed, forKey: "lastUsed")
}
required init?(coder aDecoder: NSCoder) {
if let locatieNaam : String = aDecoder.decodeObjectForKey("locatieNaam") as? String {
//This is the OLD object
name = locatieNaam
let nullableLocation : CLLocation? = aDecoder.decodeObjectForKey("locatie") as? CLLocation
if let notnulllablelocation : CLLocation = nullableLocation {
location = notnulllablelocation
} else {
location = CLLocation.init(latitude: 0, longitude: 0) //Not possible
}
lastUsed = aDecoder.decodeObjectForKey("lastUsed") as? NSDate
if aDecoder.decodeBoolForKey("isThuis") {
type = .Home
} else if aDecoder.decodeBoolForKey("isWerk") {
type = .Work
} else if aDecoder.decodeBoolForKey("isFavoriet") {
type = .Favoriet
} else {
type = .Other
}
address = nil
}
else {
name = aDecoder.decodeObjectForKey("name") as! String
let nullableLocation : CLLocation? = aDecoder.decodeObjectForKey("location") as? CLLocation
if let notnullableLocation : CLLocation = nullableLocation {
location = notnullableLocation
} else {
location = CLLocation.init(latitude: 0, longitude: 0) //Not possible
}
lastUsed = aDecoder.decodeObjectForKey("lastUsed") as? NSDate
type = PlaceType.init(rawValue: aDecoder.decodeInt32ForKey("type"))!
address = aDecoder.decodeObjectForKey("address") as? String
}
}
}
Reading from NSUserDefaults:
+ (Place*)WorkPlace;
{
#try {
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:kSharedUserDefaults];
NSData *result = [mySharedDefaults objectForKey:kWerkBestemming];
if(result == NULL)
return nil;
[NSKeyedUnarchiver setClass:[Place class] forClassName:#"Bestemming"];
[NSKeyedUnarchiver setClass:[Place class] forClassName:#"BestemmingBase"];
Place *place = [NSKeyedUnarchiver unarchiveObjectWithData:result];
if(place != nil) {
place.type = PlaceTypeWork; //Needed because the old Bestemming class didnt saved the boolean isWerk
}
return place;
}
#catch (NSException *exception) {
return nil;
}
}
The crash log says it crashes on line 0, which is comment so I think it crashes in the init method and I think it has something to do with an object which is null but could not be null.
What i've tried:
Try catch in SharedUserDefaultsManager
Extra checks on non-nullables
For those users where the app crashes I can live with removing the object from NSUserDefaults. Only if I can know when it happens.
Think this is a much better approach to deal with the NSCoding init method and return nil if variables are not what you are expecting:
required convenience init?(coder decoder: NSCoder) {
guard let title = decoder.decodeObjectForKey("title") as? String,
let author = decoder.decodeObjectForKey("author") as? String,
let categories = decoder.decodeObjectForKey("categories") as? [String]
else { return nil }
self.init(
title: title,
author: author,
pageCount: decoder.decodeIntegerForKey("pageCount"),
categories: categories,
available: decoder.decodeBoolForKey("available")
)
}
From NSHipster: http://nshipster.com/nscoding/
Now let's see how the new version is working out.
Edit: it worked!