This issue relates to another issue reported on the Apple Developer forum titled How to avoid Data Races in deinit from 4 years ago. I am seeing crashes in production related to associated data and outlined consume code added by the compiler to deinitialize enums with associated data that contain reference types.
When trying to find if someone else has faced the same issue, I stumbled across the above post. I reduced the example from that post to a simpler example below and reliably get a crash due to bad access. (I ran this in Playground and got the crash but no stack trace)
import Foundation
class Racer {
let queue = DispatchQueue(label: "Racer-\(UUID())")
var value: String? = "" // Desugars to Optional<String>, an enum
func race() {
queue.async {[weak self] in
self?.value = UUID().uuidString
}
}
}
let racer = Racer()
while true {
racer.race()
}
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x357d20cc94c0).
Is this a bug in Swift that has yet to be patched?
I'm new to both Xcode and Swift (...and serious Swift programming) and am hoping someone can help me figure out how to view / access the values of this class object.
I have this code in my ViewController.swift for invoking my REST API (via AWS API Gateway) and am attempting to print result to the console. Clearly, all I'm doing here is printing the address of the class object:
#IBAction func userInvokeApi(_ sender: UIButton) {
print("You clicked invoke api...")
let client = SVTLambdaGateClient.default()
client.calcGet(operand2: "3", _operator: "+", operand1: "5").continueWith{ (task: AWSTask?) -> AnyObject? in
if let error = task?.error {
print("Error occurred: \(error)")
return nil
}
if let result = task?.result {
// Do something with result
print("The result is... \(result)")
}
return nil
}
}
Here's what prints:
You clicked invoke api...
The result is... <AmplifyRestApiTest.Empty: 0x600002020770> {
}
(where AmplifyRestApiTest is the name of my Xcode project. Though I'm NOT using AWS Amplify to build this project; mainly because I've run into problems using it.)
I do have this Empty class in Empty.swift that is part of the API Gateway generated iOS Swift SDK:
import Foundation
import AWSCore
#objcMembers
public class Empty : AWSModel {
public override static func jsonKeyPathsByPropertyKey() -> [AnyHashable : Any]!{
var params:[AnyHashable : Any] = [:]`
return params
}
}
Now, when I set a breakpoint on the print statement this is what I see:
Can someone please tell me why I don't see the values relating to this object? What's the strategy for unpacking this API response??
I know that I'm invoking the REST API successfully because I can see (via Cloudwatch logs) that it's returning the result to the Client. So this post is just my attempt to access the corresponding Object.
Another detail: I'm using an API Gateway generated iOS Swift SDK and I followed all of the tutorial instruction for using the SDK in my project.
use lldb command po to print the object.
(lldb) po #"lunar"
lunar
(lldb) p #"lunar"
(NSString *) $13 = 0x00007fdb9d0003b0 #"lunar"
I would suggest going over the docs here...
https://cocoapods.org/pods/AWSCore#getting-started-with-swift
Did you import appropriate headers?
Hope this points you in the right direction.
Xcode 8 or 9 started displaying runtime issues. You see a purple icon at the top of the window, and a list in Issue Navigator, next to buildtime issues like compilation warnings and errors.
The runtime issues I've seen are created by the system libraries. Is there a way for my own application code to generate these?
Yes! You'll see these if you do something that a sanitizer catches, like performing certain UI operations a background thread with Thread Sanitizer enabled. Having an ambiguous layout and pausing in the view debugger is also a way to get this to occur. Either way, seeing this occur in Apple's libraries isn't a good thing…
UPDATE: I looked into how these warnings are hit, and LLDB essentially sets a breakpoint on a set of magic functions (__asan::AsanDie(), __tsan_on_report, __ubsan_on_report, __main_thread_checker_on_report) inside of a sanitizer dynamic library that are called when issues occur. If you define your own version of these functions and call them, you'll get the warning to show up. First, create the symbol somewhere in your project:
void __main_thread_checker_on_report(char *message) {
}
Then you can trigger it at will, just by putting this code anywhere in your application (you probably want to hide it behind a macro):
((void (*)(char *))dlsym(dlopen(NULL, RTLD_LAZY), "__main_thread_checker_on_report")))("This will show up as a warning")
Needless to say, this will almost certainly not play nicely with the actual sanitizer if you choose to use it. You should probably compile the above conditionally based on whether you are using a sanitizer or not.
In XCode 8.3 and earlier you can use set breakpoint into any method of UIKit class like setNeedsDisplay() like below.
Also there is library in objective-c steipete class in which #import <objc/runtime.h> is used.
But in Xcode 9 below library Xcode.app/Contenets/Developer/usr/lib/libMainThreadChecker.dylib is available, Which handle for any relevant issues potentially performed out-of-main thread at runtime.
Well, that's a hack, far from ideal, but can by useful to get runtime warnings without having game-over behavior like in assertions or fatal errors:
func runtimeWarning(_ message: String, file: String = #file, line: Int = #line) {
#if DEBUG
DispatchQueue.global(qos: .userInteractive).async {
// If you got here, please check console for more info
_ = UIApplication.shared.windows
print("Runtime warning: \(message): file \(file.fileName), line \(line)")
}
#endif
}
fileprivate extension String {
var fileName: String { URL(fileURLWithPath: self).lastPathComponent }
}
Unfortunately this leads to quite a big print to console from Main Thread Checker, also does not show on correct line, but at least you have all info needed in console (including line of code you should check).
Usage and result is very similar to assertionFailure or fatalError:
runtimeWarning("Hi, I'm purple")
leads to message in console:
Runtime warning: Hi, I'm purple: file MyFile.swift, line 10
and this, so you won't miss it:
Just wanted to add a Swift implementation of a runtimeWarning method, for anyone curious:
func runtimeWarning(_ message: String) {
// Load the dynamic library.
guard let handle = dlopen(nil, RTLD_NOW) else {
fatalError("Couldn't find dynamic library for runtime warning.")
}
// Get the "__main_thread_checker_on_report" symbol from the handle.
guard let sym = dlsym(handle, "__main_thread_checker_on_report") else {
fatalError("Couldn't find function for runtime warning reporting.")
}
// Cast the symbol to a callable Swift function type.
typealias ReporterFunction = #convention(c) (UnsafePointer<Int8>) -> Void
let reporter = unsafeBitCast(sym, to: ReporterFunction.self)
// Convert the message to a pointer
message.withCString { messagePointer in
// Call the reporter with the acquired messagePointer
reporter(messagePointer)
}
}
CocoaLumberjack framework can be used to capture Run times console logs as well as App's Background wakeup logs.
https://github.com/CocoaLumberjack/CocoaLumberjack
https://github.com/phonegap/phonegap-plugin-push/issues/1988
This way you can capture purple warnings displayed in Xcode9 like below in a file that is maintained inside App Container:-
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication registerUserNotificationSettings:]
PID: 2897, TID: 1262426, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 21
It depends on you if you are doing any UI related stuff on other then main thread so system will generate for you else you can not manually generate it.
All UI manipulations should be done in the Main Thread.
If you are not doing this so, in XCode 9 have feature called Main thread checker.
For more info, you can visit below url: https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
It is basically used to checks whether any UIKit related stuff is happening on a main thread or not ?, If failed to do so, it will produce issues at Runtime. So wrap your code in Main Thread block like below to avoid glitches and runtime warnings.
You can Enable - Disable using this steps Edit Scheme... -> (Select your scheme) -> Diagnostics -> Disable 'Main thread checker'
Swift Composable Architecture folks dug into this and found a solution
You should read about it here
And you can get the code here
which you can then use as
runtimeWarning("This is neat")
full code because SO likes code rather than references:
#if DEBUG
import os
import XCTestDynamicOverlay
// NB: Xcode runtime warnings offer a much better experience than traditional assertions and
// breakpoints, but Apple provides no means of creating custom runtime warnings ourselves.
// To work around this, we hook into SwiftUI's runtime issue delivery mechanism, instead.
//
// Feedback filed: https://gist.github.com/stephencelis/a8d06383ed6ccde3e5ef5d1b3ad52bbc
private let rw = (
dso: { () -> UnsafeMutableRawPointer in
let count = _dyld_image_count()
for i in 0..<count {
if let name = _dyld_get_image_name(i) {
let swiftString = String(cString: name)
if swiftString.hasSuffix("/SwiftUI") {
if let header = _dyld_get_image_header(i) {
return UnsafeMutableRawPointer(mutating: UnsafeRawPointer(header))
}
}
}
}
return UnsafeMutableRawPointer(mutating: #dsohandle)
}(),
log: OSLog(subsystem: "com.apple.runtime-issues", category: "ComposableArchitecture")
)
#endif
#_transparent
#inline(__always)
func runtimeWarning(
_ message: #autoclosure () -> StaticString,
_ args: #autoclosure () -> [CVarArg] = []
) {
#if DEBUG
let message = message()
unsafeBitCast(
os_log as (OSLogType, UnsafeRawPointer, OSLog, StaticString, CVarArg...) -> Void,
to: ((OSLogType, UnsafeRawPointer, OSLog, StaticString, [CVarArg]) -> Void).self
)(.fault, rw.dso, rw.log, message, args())
XCTFail(String(format: "\(message)", arguments: args()))
#endif
}
code is MIT licenced
I'm looking for a way to programmatically list any nearby Bluetooth devices (discoverable) that my device finds. I have not been able to find any information or tutorials regarding performing this call in Swift 3.0. This Q-A post discusses finding these devices using Swift 1.0 and building in Xcode 6, rather than the latest version 8.
I did my best to try to make my code into the 3.0 Syntax from the 1.0, but while running the following code, nothing is returned in the Playground:
import Cocoa
import IOBluetooth
import PlaygroundSupport
class BlueDelegate : IOBluetoothDeviceInquiryDelegate {
func deviceInquiryComplete(_ sender: IOBluetoothDeviceInquiry, error: IOReturn, aborted: Bool) {
aborted
print("called")
let devices = sender.foundDevices()
for device : Any? in devices! {
if let thingy = device as? IOBluetoothDevice {
thingy.getAddress()
}
}
}
}
var delegate = BlueDelegate()
var inquiry = IOBluetoothDeviceInquiry(delegate: delegate)
inquiry?.start()
PlaygroundPage.current.needsIndefiniteExecution = true
Using IOBluetooth the Correct Way
The following code works flawlessly in Xcode Version 8.2.1 (8C1002), Swift 3.0. There are a few lines that aren't required, such as the entire method of deviceInquiryStarted.
Update: These usages still work as of Xcode 9.2 (9B55) and Swift 4.
Playground
import Cocoa
import IOBluetooth
import PlaygroundSupport
class BlueDelegate : IOBluetoothDeviceInquiryDelegate {
func deviceInquiryStarted(_ sender: IOBluetoothDeviceInquiry) {
print("Inquiry Started...")
//optional, but can notify you when the inquiry has started.
}
func deviceInquiryDeviceFound(_ sender: IOBluetoothDeviceInquiry, device: IOBluetoothDevice) {
print("\(device.addressString!)")
}
func deviceInquiryComplete(_ sender: IOBluetoothDeviceInquiry!, error: IOReturn, aborted: Bool) {
//optional, but can notify you once the inquiry is completed.
}
}
var delegate = BlueDelegate()
var ibdi = IOBluetoothDeviceInquiry(delegate: delegate)
ibdi?.updateNewDeviceNames = true
ibdi?.start()
PlaygroundPage.current.needsIndefiniteExecution = true
Project-Application Usage
import Cocoa
import IOBluetooth
import ...
class BlueDelegate : IOBluetoothDeviceInquiryDelegate {
func deviceInquiryStarted(_ sender: IOBluetoothDeviceInquiry) {
print("Inquiry Started...")
}
func deviceInquiryDeviceFound(_ sender: IOBluetoothDeviceInquiry, device: IOBluetoothDevice) {
print("\(device.addressString!)")
}
}
//other classes here:
//reference the following outside of any class:
var delegate = BlueDelegate()
var ibdi = IOBluetoothDeviceInquiry(delegate: delegate)
//refer to these specifically inside of any class:
ibdi?.updateNewDeviceNames = true
ibdi?.start() //recommended under after an action-button press.
Explanation
The issue I was originally faced with was trying to access the information as the inquiry was still in process.
When I accessed it, under many different occasions my playground would hang and I would be forced to force quit both Xcode.app, and com.apple.CoreSimulator.CoreSimulatorService from the Activity Monitor. I lead myself to believe that this was just a Playground bug, only to learn that my application would crash once the inquiry finished.
As Apple's API Reference states:
Important Note: DO NOT perform remote name requests on devices from delegate methods or while this object is in use. If you wish to do your own remote name requests on devices, do them after you have stopped this object. If you do not heed this warning, you could potentially deadlock your process.
Which entirely explained my issue. Rather than directly asking for the IOBluetoothDevice information from the sender.foundDevices() method (which I believe may not have been updating..?) I simply used the parameters built into the function to mention that it was indeed an IOBluetoothDevice object, and simply to ask for that information to be printed.
Final Note
I hope that this Q/A I've created helps others in need when using IOBluetooth in Swift. The lack of any tutorials and the high amounts of outdated, Objective-C code made finding this information very challenging. I'd like to thank #RobNapier for the support on trying to find the answer to this riddle in the beginning. I'd also like to thank NotMyName for the reply on my post on the Apple Developer Forums.
I will be exploring the usage of this in an iOS device more sooner than later!
I have issues getting Complications to work. It would be helpful if I was able to reliably refresh them.
Therefore I linked a force-press menu button to the following method
#IBAction func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications {
complicationServer.reloadTimelineForComplication(complication)
}
}
Unfortunately this leads to the app crashing. with a fatal error: unexpectedly found nil while unwrapping an Optional value.
I understand that calling reloadTimelineForComplication(complication) is budgeted but that can't be the issue here as it doesn't work from the very beginning.
I am currently using watchOS2 + Xcode 7 GM
I'd appreciate any ideas on making Complications refresh while the app is running?
Trace or use the exception breakpoint and focus on reading the whole error message where it tells you exactly on which line it found the nil unexpectedly (I do suspect the complicationServer). Use 'if let' instead of 'let' to force unwrap the respective variable.
private func reloadComplications() {
if let complications: [CLKComplication] = CLKComplicationServer.sharedInstance().activeComplications {
if complications.count > 0 {
for complication in complications {
CLKComplicationServer.sharedInstance().reloadTimelineForComplication(complication)
NSLog("Reloading complication \(complication.description)...")
}
WKInterfaceDevice.currentDevice().playHaptic(WKHapticType.Click) // haptic only for debugging
}
}
}