I’m writing an app that burns to optical disks and there’s a strange problem when returning from the burn progress panel.
I call the disk recording setup sheet like this:
let setup_panel = DRBurnSetupPanel()
let passed = UnsafeMutableRawPointer(Unmanaged.passUnretained(self.disk_buckets[current_burn_disk]).toOpaque())
setup_panel.beginSetupSheet(for: self.window, modalDelegate: self, didEnd: #selector(self.burnSetupPanelDidEnd(_:return_code:context_info:)), contextInfo: passed)
disk_buckets is an array of classes each containing a reference to a DRTrack to be burnt - I pass an element so that I can deal with the DRTrack reference later.
After the setup panel is dismissed, the following method is then called:
func burnSetupPanelDidEnd(_ panel: DRBurnSetupPanel, return_code: Int, context_info: UnsafeMutableRawPointer) {
//…. some code ….
var track:DRTrack = self.disk_buckets[self.current_burn_disk].vDRTrack!
NotificationCenter.default.addObserver(self, selector: #selector(self.progressDidEnd), name: NSNotification.Name(rawValue: BTVDiscBurnDidEndNotification), object: nil)
self.objc_panel.presentDiscProgressPanel(self.window, burner: panel.burnObject(), layout: track!)
}
objc_panel is a obj-c singleton that initialises and presents a disc burning progress panel (I did it this way as doing it in Swift is buggy - the progress panel is displayed as a tiny window instead of the default OS one - bug report has been sent to Apple). At the end of the burn objc_panel posts the BTVDiscBurnDidEndNotification notification to let the AppDelegate know it’s finished and so to call:
func progressDidEnd(_ note: Notification?) {
print (“DEBUG count: \(self.disk_buckets.count)")
print (“DEBUG first element: \(self.disk_buckets[0])")
//…. more code ….
}
All goes well until the end of the chain when any attempt to access the first element (or any, for that matter) causes a crash:
2016-10-04 14:01:34.654 DiskSpan[4025:220213] *** -[DiskSpan.BackupDisk retain]: message sent to deallocated instance 0x6000cafc0f40
(BackupDisk being the class that populates the array)
However, the first line prints out a correct count of the array i.e. 1. So how come I can't access anything in the array during a notification post?
EDIT: I tried appending a dummy item to the array before reading it back and still the crash only occurs when trying to read the array - not write to it.
It should be noted that this worked under Swift 2 and has only become a problem since Swift 3!
It turns out to be a retention problem. After the call to the obj-c class to start the setup window for burning, the elements in disk_buckets are all over-released. It was a hack but I enumerated over the elements and assigned them to a new array just before calling the setup panel.
Related
I am attempting to add a recipient dynamically to the requiredAttendees for an Outlook appointment
var arr = [{emailAddress: 'test#example.com', displayName: 'Test Name'}]
Office.context.mailbox.item.requiredAttendees.addAsync(arr)
(also fails with arr = ['test#example.com'])
and it is throwing an error
Sys.ArgumentException: Sys.ArgumentException:
Value does not fall within the expected range.
How might that be accomplished?
Cf. docs which I am following
Cf. Radio-silence Github issue
UPDATE SCREEN SHOTS
PRE-THROW
You can notice that n is correctly defined as an array with 1 value (right panel)
Checking the same array as arr from the console evaluates to true
Throw
The script is throwing on evaluation (as indicated by the light green highlight)
To get dynamic URL params, I am loading an iframe onInit when Office is done initializing.
Though the rest of the API is available to the loaded iframe when passed in, there is something inherent to this particular piece of the API that must be dependent on window.
Moving the API call outside of the iframe fixes the issue and causes it to work as expected.
I am having a problem with our approach to data persistence in our app. It was decided to use NSUserDefaults with NSCoding compliant data model, which I disagree with due to the scale of our app.
The problem I'm seeing is when the data model changes, any attempt to deserialized results in a crash. The app must be uninstalled and reinstalled in order to re-serialize.
Scenario:
User installs app
User does stuff.
Developer decides that a property should be added to one of the serialized objects and pushes an update.
User installs update.
App goes 'kaboom'.
This is happening because the data had been serialized with a different model than it is now attempting to be deserialized as.
Example:
class Contact: NSCoding {
var name
var address
var userId
}
... // NSCoding compliance happens next. This object gets serialized.
Someone decides that Contact needs more stuff:
class Contact: NSCoding {
var name
var address
var userId
var phoneNumber
var emailAddress
}
Attempting to deserialize the Contact object, even though the NSCoding compliance for encoding and decoding has been updated to load and deserialize, causes
fatal error: unexpectedly found nil while unwrapping an Optional value
CoreDataManager.unarchiveUser
Worker.init
So, my question is, how could we possibly avoid this crash from occurring when running an updated version of the app that has a different schema??
You're crashing because,
You are attempting to decodeObject(forKey:) on a key that doesn't exist (because it didn't exist on the class when the object was encoded). This method returns nil.
You are using ! to force-unwrap the result of #1.
As a rule of thumb, if your Swift code crashes on a line that contains a !, there's about a 95% chance that the ! is the direct cause of the crash. If the error message mentions unwrapping an optional, it's a 100% chance.
The documentation for the decodeObject(forKey:) method explains that it may return nil. In your case this is guaranteed to happen if you're upgrading from a previous version of the class and you're decoding a key that you just added.
Your code needs to recognize that there might not be a value for the new properties. The simplest fix is replacing as! with as?. Then you'll get a nil value for the new property. For properties that are not optional, you can add something like ?? "default value" to the end.
You could also use the containsValue(forKey:) method to check if a value exists before trying to decode the key.
I'm actually on swift 2.3.
Inbound Call works great with CallKit. But OutGoing Call ....
I saw the SpeakerBox project, I do the same things.
But it doesn't work.
To start my call, I used
let handle = CXHandle(type: .PhoneNumber, value: "TOTO")
let startCallAction = CXStartCallAction(callUUID: uuid, handle: handle)
startCallAction.video = video
let transaction = CXTransaction()
transaction.addAction(startCallAction)
requestTransaction(transaction)
After, in SpeakerBox Project, this function is called :
func provider(provider: CXProvider, perform action: CXStartCallAction)
But not in my project. Then, when i hangup, i see : "Call failed".
Do you have an idea ?
Be sure you are configuring your CXProvider and setting its delegate properly. If you do not set the CXProvider's delegate property, the delegate will not receive any actions to perform.
Also, if you see a "Call Failed" UI, this may indicate your app is crashing. I'd check for crash logs or run the app in the debugger.
As far as I can see, SpeakerBox demo does not perform the following provider method:
https://developer.apple.com/documentation/callkit/cxprovider/1930701-reportcall
func reportCall(with UUID: UUID,
endedAt dateEnded: Date?,
reason endedReason: CXCallEndedReason)
- (void)reportCallWithUUID:(NSUUID *)UUID endedAtDate:(nullable NSDate
*)dateEnded reason:(CXCallEndedReason)endedReason;
Which leads to the "Call failed" UI screen being displayed - as CallKit was not given a reason why the call has ended, and it seems that "
CXCallEndedReasonFailed" is assumed by default.
Call "reportCall endedAt" before requesting the CXEndCallAction transaction to remove "Call failed" screen.
Have you added the required permissions to your info.plist?
I've tried to create a Cocoa app which uses NSPopover internally. One of the popover's method is showRelativeToRect: ofView: preferredEdge:, which triggers an popover in Cocoa app.
If you use Objective-C in Xcode 5.1, you can execute the method with the method above, like this:
[popover showRelativeToRect: sender.bounds ofView: sender preferredEdge: NSMaxXEdge];
However, when I tried to use the method in Swift in Xcode 6, the message Use of unresolved identifier 'NSMaxXEdge' was shown when I wrote the following method, which is just a rewrite of the Objective-C method above:
popover.showRelativeToRect(sender.bounds, ofView: sender, preferredEdge: NSMaxXEdge
So where is the NSMaxXEdge gone? The official documentation says it is of type NSRectEdge, but what is the NSRectEdge? The doc doesn't link to NSRectEdge page.
Also, Xcode 5 documentation also says it is NSRectEdge, but again, no link exists there. So how can I know about what it is all about?
And finally, if NSMaxXEdge is no longer available in Xcode 6, what is the alternative?
In Foundation/NSGeometary.h of 10.10 SDK:
typedef enum {
NSMinXEdge = 0,
NSMinYEdge = 1,
NSMaxXEdge = 2,
NSMaxYEdge = 3
} NSRectEdge;
So it should be NSRectEdge.from(2) or NSRectEdge(2) or just pass 2 will be fine.
If you try this:
println("NSRectEdge.max: \(NSRectEdge.max)") // 9223372036854775807
println("NSRectEdge.from(2): \(NSRectEdge.from(2))") // 2
println("NSRectEdge(2): \(NSRectEdge(2))") //2
You will know that .max was actually the max positive signed Int for 64-bit.
(Tho, I can't be sure since it's not really mentioned in documentation anywhere.)
NSRectEdge has a static var called max. I think you should just use that. For example:
popover.showRelativeToRect(rect, ofView: view, preferredEdge: NSRectEdge.max)
(The below is true for beta 5 (developing for 10.9). Your mileage may vary.)
Above, you get a solution that works - passing 0-3 where the function calls for a NSRectEdge. I'd like to pick up on
how can I know about what it is all about?
The documentation indicates that NSRectEdge is bridged with CGRectEdge, but trying to pass in CGRectEdge led to an error of
CGRectEdge is not convertible to NSRectEdge
NSRectEdge.from(2) or NSRectEdge(2) - as suggested above - come back with the error that
NSRectEdge has no accessible initializers
When you type NSRectEdge into Xcode, however, it shows two types:
CGRectEdge (which in this case is useless, see above) and Int.
I'm afraid that you need to guess that NSRectEdge is an enum when you see it both called as a string and defined as an int; but from there to looking up its definition in the framework is a logical step; as is guessing that you will have four values, one for each edge.
Incidentally, there seems to be an internal modulo operation going on somewhere - when you pass it '4', you get NSMinXEdge again and so on.
I am trying to create a Game so that I can change its data and save it back. I get two errors that are on the commented lines. Why am I getting these errors. I allocated the Game so I should have to release it correct. Here is my code to save my Game
Game *newGame = [[Game alloc] init];//error 1
newGame = [gamesArray objectAtIndex:gameNumber];
[newGame setTheShotArray:shotArray];
[gamesArray replaceObjectAtIndex:gameNumber withObject:newGame];
NSString *path = [self findGamesPath];
[NSKeyedArchiver archiveRootObject:gamesArray toFile:path];
[newGame release];//error 2
I get error 1 which says Value stored to 'newGame' during its initialization is never read.
The second error says Incorrect decrement of the reference count of an object that is not owned at this point by the caller.
What does this mean? And please don't tell me, you need to read up on memory management and just give me a link. Tell me how to fix the problem please.
Game *newGame = [[Game alloc] init];//error 1
You create a new instance and you own it since you’ve used +alloc.
newGame = [gamesArray objectAtIndex:gameNumber];
You obtain another instance from gamesArray and assign it to the same variable that was used in the previous line. This means that you’ve lost the reference to the previous object and, since you own the previous object, you’re responsible for releasing it. You don’t, so you’re leaking that object.
[newGame release];//error 2
At this point newGame points to the instance via from gamesArray. You do not own it since you haven’t obtained it via NARC, hence you should not release it.
NARC: a method whose name contains new, alloc, copy, or is retain.
Bottom line: you’re leaking the object that you’ve created via +alloc and you’re trying to release an object that you do not own.