"target is not running or doesn't have entitlement" message: is this connected to crashes? - swift

Update: this problem is more focused now, and not on quite the same topic. I've asked this question as a follow-on
ORIGINAL QUESTION:
I am getting a crash on a subclassed WKWebView-provisioned app.
ProcessAssertion::acquireSync Failed to acquire RBS assertion 'ConnectionTerminationWatchdog' for process with PID=87121, error: Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit" UserInfo={NSLocalizedFailureReason=target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit}
The problem is, that I can't tell if this is related or not. The actual error on crash is
Thread 1: EXC_BAD_ACCESS (code=1, address=0xbdb2dfcf0470)
Which I was assuming was something running off the end of an array. This makes some sense: I'm selecting from a table that filters out some entries from the data source; but I've checked that carefully; there is no point when a row index greater than the actual rows is accessed (and yes, I'm accounting for the difference between count and index).
The main change here is that I previously had a UIView that acted as a container for a number of CAShapeLayers. I also wanted to overlay text view, but with the proviso that this be via a WKWebView. With two separate views, I would have to either have the CAShapeLayer objects in front of, or behind the WebView. I was seeking a fix to that.
What I have done is substitute a WKWebView for the original UIView. I can add the CAShapes to it, so it performs the original function. It also can, presumably, display the html. And the original suggestion in this answer to a question I asked is what I am working towards. The idea being that it would allow the effect sought, with shapes in front of or behind the html elements.
But the error is thrown after the DidSelect call on the table:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
Tracker.track("getting row \(indexPath.row)")
let ptv = tableView as? NovilloTableView
if ptv!.uiType == .textTable {
let gp = Projects.currentProject?.getPaths(type: PaletteView.getCurrentPane())
GitPaths.currentGitPath = gp![indexPath.row]
NotificationCenter.default.post(name: NNames.updateWebText.nn(), object: nil)
return
}
let svgs = Projects.currentProject!.getPaths(type : PaletteView.getCurrentPane())
var gitPath = svgs[indexPath.row]
var gitPaths = GitPaths.getMediaBoundingBoxes(paths: [gitPath])
guard let pathArrays = gitPath.parseForRegBeziers() else { return }
let rslt = pathArrays.0
let regBeziers = pathArrays.1
gitPath.boundingBox = gitPath.getBoundsParamsForPaths(src: regBeziers.isEmpty ? rslt : regBeziers)
GitPaths.currentGitPath = gitPath
// Tracker.track("sending notification")
NotificationCenter.default.post(name: NNames.updateMedia.nn(), object: nil,
userInfo: ["path" : gitPath])
Tracker.track("completed didSelect")
return
}
In other words, the interaction has ended; but I get this crash, even though I can se that the expected result (the rendering of the shapes into the view) has been completed correctly. It seems to be happening right after everything has completed, and no amount of breakpoints has shown anything else to be happening.
This is confusing to me, and I have hit a limit on what I know how to do to dig further into this. Given the nature of web connections, I've wondered if it's some asynchronous issue that I can't debug sequentially; but that's guesswork without any direct evidence.
I suspect that there is a possible configuration problem with the WebView that shows up once I interact with it, by changing its contents. I'm not actually trying to get it to load anything when it crashes, it's only performing its original function as a container for the CAShapeLayers, so I'm confused.
The main view that contains the WKWebView (which is subclassed, to support a function to determine if it should display the web content, and which I've commented out), is set as the delegate for the WKWebView, and that seems to be fine, though there are no actual protocol functions added to that view, not sure if that matters.
The other detail is that the WebView when it does load web content is only loading local text, and not connected to any services. This testing is happening in the Simulator, and I've come across advice elsewhere to allow for background processes that include enabling Background Fetch, etc., but this has done nothing to change the situation...
EDIT: this is the extent of the configuration of the subclassed WKWebView: maybe this is the issue?
mediaDisplay = NovilloWebView()
mediaPane.addSubview(mediaDisplay)
mediaDisplay.navigationDelegate = self
mediaDisplay.uiDelegate = self
mediaDisplay.backgroundColor = .clear

Related

How to get "Area under aircraft unsuitable for landing" message?

When I initiate auto-landing in the DJI Fly app I sometimes get the following message, especially under bad lighting conditions:
Now, in my own code, when I call DJIFlightController.startLandingWithCompletion, the drone would not land and the completion block gets executed without any error.
My question is, how can I intercept the equivalent to DJIs error message as shown above? What code is relevant for that?
EDIT 1:
I am also checking if a landing confirmation is needed with the following code:
func observeConfirmLanding() {
guard let confirmLandingKey = DJIFlightControllerKey(param: DJIFlightControllerParamConfirmLanding) else { return }
DJISDKManager.keyManager()?.startListeningForChanges(on: confirmLandingKey, withListener: self) { (oldValue: DJIKeyedValue?, newValue: DJIKeyedValue?) in
DispatchQueue.main.async {
if let oldBoolValue = oldValue?.boolValue,
let newBoolValue = newValue?.boolValue,
oldBoolValue != newBoolValue {
self.landingConfirmationNeeded = newBoolValue
self.logger.debug("Landing confirmation is needed")
}
}
}
}
It never enters the closure.
As I understood the landing confirmation might be needed at a height of 0.3m, but in my case, the landing process gets interrupted at different heights that are more than 0.3m, e.g. already at 2m or 1.5m
EDIT 2:
I have changed the surface below the drone in my basement by adding a bright carpet with a distinct pattern. This improves the whole stability of the drone AND even more important: The drone just lands without being interrupted. I do not get the warning message in the DJI Fly app any more.
I check for isLandingConfirmation the way Brien suggests in his comment, I finally get true when testing this in the simulator.
extension FlightControllerObserver: DJIFlightControllerDelegate {
func flightController(_ fc: DJIFlightController, didUpdate state: DJIFlightControllerState) {
if (landingConfirmationNeeded != state.isLandingConfirmationNeeded) {
landingConfirmationNeeded = state.isLandingConfirmationNeeded
}
}
But, when I test this in my basement (flight mode "OPTI") and outside (flight mode "GPS") the drone just lands without waiting for any confirmation.
While I learned a lot, it is still a miracle to me which class in the DJI Mobile SDK is responsible for "throwing" that warning message.
If the completion handler completes without any error you might need to check if isLandingConfirmationNeeded in DJIFlightControllerState is set to true. If thats the case then you will need to implement the function confirmLandingWithCompletion.
Sounds relevant to your experience looking at the documentation
(void)confirmLandingWithCompletion:(DJICompletionBlock)completion Confirms continuation of landing action. When the clearance between
the aircraft and the ground is less than 0.3m, the aircraft will pause
landing and wait for user's confirmation. Can use
isLandingConfirmationNeeded in DJIFlightControllerState to check if
confirmation is needed. It is supported by flight controller firmware
3.2.0.0 and above.
The landingProtectionState property of the DJIVisionControlState class could be a good place to look for the cause of that error message. One of the potential states that sounds relevant is
DJIVisionLandingProtectionStateNotSafeToLand -> Landing area is not flat
enough to be considered safe for landing. The aircraft should be moved
to an area that is more flat and an auto-land should be attempted
again or the user should land the aircraft manually.
Also within a section of DJI's documentation there is a section on an article about flight control that talks about landing protection and forcing a landing. I couldn't see any functions in the SDK to force a landing.
You should be aware of that the fly app does not use the sdk internally. It uses the middlelayer directly.
You often get different behaivor when using the SDK compared to the app. Some functions are not available at all.
I usually disable it completly, I want it to land when I say so :-)
(exit_landing_ground_not_smooth_enable g_config.landing.exit_landing_ground_not_smooth_enable)

Accessing a NSTableviews custom Tablecellview

I made a NSTableview and a custom tablecellview-class "KSTablecellview" which defines the cells inside the tableview.
Now I'm trying to access these cells and the elements inside them at a certain time, for example triggered through an users input.
For example I wanna change the text of a textfield in one of my custom cellviews. I tried that:
Outlet_TableView.selectRowIndexes(IndexSet(integer: 0), byExtendingSelection: false) // Selecting row #1
let view = Outlet_TableView.view(atColumn: 0, row: 0, makeIfNecessary: false) as! KSTableCellView // getting cellview, at first row/ first column (-> crashes)
view.myTextField.stringvalue = "Hello World"
This fails giving me "[...] [default] Unable to load Info.plist exceptions (eGPUOverrides)"
I tried some other things and tried to work out the problems reason, but I wasn't able to do it, I'm still a beginner.
Any help would be really great.
I'm using XCode and Swift, trying to build an app for Mac OS.
You should try to avoid updating the content of your cells manually. Instead, you should reload the data from your data source.
func reloadData(forRowIndexes rowIndexes: IndexSet,
columnIndexes: IndexSet)
Which will in turn fetch the data from your data source at the given index/column.
For example, your data source would probably contain "Hello World" at the given index after the user event occurred (provided you updated your data source content), and would thus be used in the dataCellFor: delegate method.
May be you're doing these operations before table is loaded for the first time(eg. inviewDidLoad) or on tableView with numberOfRows = 0.
Until tableView loads that row, it won't create the views inside that row and tableView.view(atColumn:, row:, makeIfNecessary: false) will return nil and force unwrapping this nil will make your application crash.

When are Realm notifications delivered to main thread after writes on a background thread?

I'm seeing crashes that either shouldn't be possible, or are very much possible and the documentation just isn't clear enough as to why.
UPDATE:
Although I disagree with the comment below asking me to separate this into multiple SO questions, if someone could focus on this one I think it would help greatly:
When are notifications delivered to the main thread? Is it possible that the results on the main thread are different than they were in a previous runloop without being notified yet of the difference?
If the answer to this question is yes the results could be different than a previous runloop without notifying then I would argue it is CRUCIAL to get this into the documentation somewhere.
Background Writes
First I think it's important to go over what I am already doing for writes. All of my writes are performed through a method that essentially looks like this (error handling aside):
func write(block: #escaping (Realm) -> ()) {
somePrivateBackgroundSerialQueue.async {
autoreleasepool {
let realm = try! Realm()
realm.refresh()
try? realm.write { block(realm) }
}
}
}
Nothing crazy here, pretty well documented on your end.
Notifications and Table Views
The main question I have here is when are notifications delivered to the main thread after being written from a background thread? I have a complex table view (multiple sections, ads every 5th row) backed by realm results. My main data source looks like:
enum StoryRow {
case story(Story) // Story is a RealmSwift.Object subclass
case ad(Int)
}
class StorySection {
let stories: Results<Story>
var numberOfRows: Int {
let count = stories.count
return count + numberOfAds(before: count)
}
func row(at index: Int) -> StoryRow {
if isAdRow(at: index) {
return .ad(index)
} else {
let storyIndex = index - numberOfAds(before: index)
return .story(stories[storyIndex])
}
}
}
var sections: [StorySection]
... sections[indexPath.section].row(at: indexPath.row) ...
Before building my sections array I fetch the realm results and filter them based on the type of stories for the particular screen, sort them so they are in the proper order for their sections, then I build up the sections by passing in results.filter(...date query...) to the section constructor. Finally, I results.observe(...) the main results object (not any of the results passed into the section) and reload the table view when the notification handler is called. I don't bother observing the results in the sections because if any of those results changed then the parent had to change as well and it should trigger a change notification.
The ad slots have callbacks when an ad is filled or not filled and when that happens instead of calling tableView.reloadData() I am doing something like:
guard tableView.indexPathsForVisibleRows?.contains(indexPath) == true else { return }
tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
The problem is, I very rarely see a crash either around an index being out of bound when accessing the realm results or an invalid table view update.
QUESTIONS
Is it possible the realm changed on the main thread before any notifications were delivered?
Should table view updates other than reloadData() simply not be used anywhere outside of a realm notification block?
Anything else crucial I am missing?
There's nothing in your code snippets or description of what you're doing that jumps out at me as obviously wrong. Having a separate callback mechanism that updates specific slots independent of Realm change notifications has a lot of potential for timing related bugs, but since you're explicitly checking if the indexPath is visible before reloading the row, I would expect that to at worst manifest as reloading the wrong row and not a crash.
The intended behavior is that refreshing the Realm and delivering notifications is an atomicish operation: anything that causes the read version to advance will deliver all notifications before returning. In simple cases, this means that you'll never see the new data without the associated notification firing first. However, there's some caveats to this:
Nested notification delivery doesn't work correctly, so beginning a write transaction from within a notification block can result in a notification being skipped (merely calling refresh() can't cause this, as it's just a no-op within a notification). If you're performing all writes on background threads you shouldn't be hitting this.
If you have multiple notification blocks, then obviously anything which gets invoked from the first one will run before the second notification block gets a chance to do things, and a call to tableView.reloadData() may result in quite a lot of things happening within the notification block. If this is the source of problems, you would hopefully see exceptions being thrown with a stack trace coming from within a notification block.

Forcing update to placeholder complication on Apple Watch

Here a simple issue I am facing while starting to experiment with WatchKit and complications.
I created a simple app which is showing a complication with a public string “Y” and by clicking it, the Apple Watch app is shown with a simple switch.
I wrote my code in getPlaceholderTemplateForComplication in ComplicationController.swift and added a switch IBAction in InterfaceController.swift.
By changing the value of the switch, the public string cycles between “N” and “Y”. I would like to have it changed in the complication as well. However I am noticing that the complication stays as it is initially at “Y”.
I found a similar question about forcing complication updates, but it was related to a TimeLine complication func and not placeHolder.
func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications {
complicationServer.reloadTimelineForComplication(complication)
}
}
It is not clear to me on where and how to use this in my case.
As suggested I worked on getCurrentTimelineEntryForComplication .
In order to test a ModularComplication only, I used:
switch complication.family {
case .ModularSmall:
let modularSmallTemplate =
CLKComplicationTemplateModularSmallRingText()
modularSmallTemplate.textProvider =
CLKSimpleTextProvider(text: stringa)
modularSmallTemplate.fillFraction = 0.95
modularSmallTemplate.ringStyle = CLKComplicationRingStyle.Closed
let template = CLKComplicationTimelineEntry(
date: NSDate(), complicationTemplate: modularSmallTemplate)
handler(template)
default:
handler(nil)
}
I have the switch IBAction in InterfaceController.swift.
I am encountering issues in using:
func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications {
complicationServer.reloadTimelineForComplication(complication)
}
}
Where do I have to write the above mentioned func, in order to be able to call it from inside the IBAction?
If I write it in ComplicationController.swift, by calling it from the IBAction in InterfaceController.swift as:
ComplicationController.updateComplication()
I get the error “Missing argument for parameter #1 in call”,
while if I write it in InterfaceController and call it in the IBAction, although the build is successful, when running the App and changing the value of the switch I get the following error: “fatal error: unexpectedly found nil while unwrapping an Optional value” on the line:
for complication in complicationServer.activeComplications
of func updateComplication.
It's not the placeholder text that you want to update. The placeholder template is a static template that's displayed in the selection screen for your complication while you are customizing your watch face. It's only called once to get the placeholder text, and doesn't get called when a timeline is reloaded.
The complication's current (actual, live) timeline entry is provided by getCurrentTimelineEntryForComplication. This function is where you should use your model's on state of the switch to create a CLKTextProvider containing a "N" or "Y" for the active complication family.
Finally, you should call updateComplication() from your switch IBAction to reload your complication timeline, which would update the current entry to show the new state of the switch on the watch face.
Since your complication is updated manually, you should return a nil updateDate in getNextRequestedUpdateDateWithHandler to avoid scheduling your complication for any regular updates.
Update for your edited question:
You should include the updateComplication function in your interface controller, as your complication controller isn't meant to be instantiated by you.
In regard to the "Unexpectedly found nil while unwrapping an Optional value" error, this is an issue that has been mentioned on the Apple Developer Forums.
If you are already running watchOS 2.1, you could try the latest watchOS beta to see if the issue has been fixed yet for 2.2. You should also file a bug report and dupe radar 22947535.

NSDocument: how do you save & restore a document's window position?

I have a NSDocument-based app, and I'd like my window positions to be saved and restored when re-opening documents. Apple's documentation on this is pretty sparse, but what I've been able to piece together is that at some point, something in the app needs to call NSWindow.setFrameUsingName() and NSWindow.setFrameAutosaveName().
What I haven't quite figured out is what point this needs to happen at, and what things need to do this. For example, this doesn't work at all:
// In my NSDocument class
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
// Add any code here that needs to be executed once the windowController has loaded the document's window.
aController.window?.setFrameUsingName("MainWindow")
aController.window?.setFrameAutosaveName("MainWindow")
}
I've read various different pieces of documentation or forum answers that point to awakeFromNib() to be another area to do this, but I can't get that to work either.
I'm also confused / worried that this is somehow being affected by Auto Layout or something I've done wrong in Interface Builder - for example, this is how my window is set up in IB:
I don't particularly want my window centered, but the other options seem to lock it in place in fixed horizontal or fixed vertical positions, which I also don't really want. A side effect of having my window be centered is that my document windows no longer cascade, which I neither want nor can seem to stop from happening (note that windowController.shouldCascadeWindows = true isn't helping either).
So - what's going on here? I'm finding knowledge on this topic to be particularly unclear or misleading, and likely out of date for Cocoa development 2015, so a modern refresher on this would be great.
Step 1: In IB, give the window an autosave name.
Step 2: There is no step 2.
The easiest place to set the name of the autosave name for the window frame is probably in your implementation of NSDocument.
If you override makeWindowControllers() as part of the implementation, you are creating the window controller(s) manually, and thus can set the name there:
override func makeWindowControllers() {
let storyboard = NSStoryboard(name: NSStoryboard.Name("MyDocumentStoryboard"), bundle: nil)
let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("MyDocument Window Controller")) as! MyDocumentWindowController
// this assumes you have a stored property or a computed property `someUniqueIdentifier` that is as unique as possible for your document
// and that you store on disk together with the rest of the document properties
windowController.windowFrameAutosaveName = NSWindow.FrameAutosaveName(rawValue: someUniqueIdentifier)
self.addWindowController(windowController)
}
If you instantiate your document window by overriding windowNibName, you should instead override the method windowControllerDidLoadNib(_:), to set the autosave name on the window. I have not tested this code, but I assume it will work:
func windowControllerDidLoadNib(_ windowController: NSWindowController) {
// this assumes you have a stored property or a computed property `someUniqueIdentifier` that is as unique as possible for your document
// and that you store on disk together with the rest of the document properties
windowController.windowFrameAutosaveName = NSWindow.FrameAutosaveName(rawValue: someUniqueIdentifier)
}