So I'm experiencing an odd error - "fatal error: unexpectedly found nil while unwrapping an Optional value"...
It's strange because it only ever fails the FIRST time I run the simulator. As long as I don't quit the simulator and just re-run the app, it will not fail, and the user location will be found successfully. If I do quit the simulator and then try to re-run the app, it will fail with the same error.
Why is this happening? Is swift somehow checking for a location before it's actually found?
Thanks in advance.
override func queryForTable() -> PFQuery! {
let query = PFQuery(className: "Yak")
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self // ? delegate
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
var userLocation:CLLocation = manager.location
currLocation = userLocation.coordinate // error occurs here
println(" my location is \([manager.location])")
if let queryLoc = currLocation {
println("ahahahaha")
query.whereKey("location", nearGeoPoint:PFGeoPoint(latitude: queryLoc.latitude as CLLocationDegrees!, longitude: queryLoc.longitude as CLLocationDegrees!), withinMiles: 10)
query.limit = 200
query.orderByDescending("createdAt")
}
My guess is that you are trying to retrieve data coming from an asynchronous service using a linear procedure.
As this line implies:
manager.startUpdatingLocation()
the manager is starting to update the location, but it doesn't mean when it returns a location has already been obtained. It can take some time time, and it can also fail.
The right place to read the location is in the didUpdateLocations method of theCLLocationManagerDelegate, which I presume you have set in the view controller.
The reason why it works the 2nd time you use it is because in the previous run the manager did have the time to detect the location, so what you're getting is the old one, and not an up to date location.
Update
One possible way of solving the problem is:
in viewDidLoad check if userLocation.coordinate is not nil (it's an implicitly unwrapped optional, so you can do that check)
if it's nil, start updating the location, add a UIActivityIndicator, maybe disable user input, and set a flag (instance property) to true, to keep track you're waiting for a location
wait for a location to be obtained in locationManager(_:didUpdateLocations:)
in that method, check if the flag is true, if it is, unset it, remove the progress view and re-enable user input, then call queryForTable
Related
Am making image library that make me abel to select multiple image from the collection view that i made
When i fun my code averting is good ,but when i press select button this error happen "EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0)"
this is the select button code
#IBAction func Select(sender: AnyObject) {
var ckeck = AssetCell() as? AssetCell
ckeck!.CheckMarkView1.hidden = false // here it shows an error which is "Thread 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
}
i had Assetcell class that contain CheckMarkView1
When you say AssetCell() as? AssetCell it means that your ckeck is an Optional, which again means that it can be something or it can be nil (nothing).
When you in the next line say ckeck!, that means that you are telling the compiler to just handle the value of ckeck and you don't care whether it is nil or not. This is almost always a bad idea as you have just found out the hard way.
A better way is to use either if let syntax to unwrap or guard syntax.
So you could say:
if let ckeck = ckeck {
ckeck!.CheckMarkView1.hidden = false
}
Or you could say:
guard let ckeck = ckeck else { return }
ckeck!.CheckMarkView1.hidden = false
That way you are sure to only start using ckeck if it actually has a value.
Having said that, the way you actually create ckeck looks a bit odd:
var ckeck = AssetCell() as? AssetCell
Now I don't know the details, but couldn't you just say
let ckeck = AssetCell()
And finally...this question has been asked a great many times already in various forms. I know that it is frustrating when you have an error and you don't quite understand what is going on, but the next time you should start with a search for EXC_BAD_INSTRUCTION for instance. This should return a lot of answers to help you solve the problem, or at least help you get a clue about what is happening. Sorry :)
I have a UI test that checks the value of static text element, waits a few seconds and checks again to confirm a change. At first it wasn't working because the hierarchy was not updating. I noticed this in the log;
Use cached accessibility hierarchy for
I've put in a workaround for this by simply adding a tap to a menu and opening/closing it so that an event is synthesized and the hierarchy is updated.
It would be better, however, if there was a way to clear the cache directly or force and update. I haven't found one in the API. Am I missing something?
Any ideas?
this is what I am doing;
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 1")
sleep(20)
menu.tap()
sleep(1)
menu.tap()
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 2")
What I'd like to be able to do it
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 1")
sleep(20)
app.elements.refresh()
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 2")
In order to force an update of the accessibility hierarchy, request the count property for any XCUIElementQuery:
// refresh
_ = XCUIApplication().navigationBars.count
// examine
print(XCUIApplication().debugDescription)
The above results in: "Get number of matches for: Descendants matching type NavigationBar" and "Snapshot accessibility hierarchy for com.myapp".
The following works for me in Xcode 10.2 (10E125):
import XCTest
extension XCUIApplication {
// WORKAROUND:
// Force XCTest to update its accessibility cache. When accessibility data
// like NSObject.accessibility{Label|Identifier} changes, it takes a while
// for XCTest to catch up. Calling this method causes XCTest to update its
// accessibility cache immediately.
func updateAccessibilityCache() {
_ = try? snapshot()
}
}
You should use expectationForPredicate, along the lines of...
let myText = app.staticTexts["myText"]
let waitFor = NSPredicate(format: "label = 'Expected 2'")
label.tap()
self.expectationForPredicate(waitFor, evaluatedWithObject: myText, handler: nil)
self.waitForExpectationsWithTimeout(2.0, handler: nil)
This will wait until either myText's label is 'Expected 2', or the timeout of 2 seconds is reached.
In my case, it is a problem because I'm trying to test for Facebook login, which uses Safari controller. It looks like Facebook has updated the UI after cache.
So you need to wait a bit, use the wait function here https://stackoverflow.com/a/42222302/1418457
wait(for: 2)
let _ = app.staticTexts.count
But the above is just workaround and very flaky. A more correct approach would be to wait for a certain element to appear, see https://stackoverflow.com/a/44279203/1418457
I was looking at adding an option for sorting available fonts by user-defined font collections (I wish Pages and Keynote did this!), but it looks like the old ways of accessing these collections are being deprecated in 10.11:
https://developer.apple.com/library/prerelease/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSFontManager_Class/index.html#//apple_ref/occ/clm/NSFontManager/
Is there a new way of accessing and using those font collections?
I've recently been working with font collections, so I may have some info for you.
The NSFontCollection API is kind of strange. It offers access to "Named Font Collections," but the names associated with said collections aren't attached to them. If that makes no sense, it's because it doesn't. However, let me try to break it down:
To add a system-wide font collection:
// Create a font descriptor (or descriptors) with whatever attributes you want
let descriptor = NSFontDescriptor(fontAttributes: nil)
// Create a font collection with the above descriptor(s)
let collection = NSFontCollection(descriptors: [descriptor])
// In Objective-C, the `+ showFontCollection:withName:visibility:error:`
// method returns `YES` if the collection was shown or `NO` if an error occurred.
// The error is passed via pointer supplied to the `error:` parameter.
//
// In Swift, the method returns `()` (aka nil literal), and instead of passing
// the error in a pointer, it `throws`, so you have to wrap the call in a `do`
// statement and catch the error (or suppress error propagation via `try!`):
do {
try NSFontCollection.showFontCollection(collection: NSFontCollection,
withName: "Visible to All Users", visibility: .Computer)
}
catch {
print("There was an error showing font collection. Info: \(error)")
}
To add a user-visible font collection:
Repeat above steps, substituting .Computer with .User:
do {
try NSFontCollection.showFontCollection(collection: NSFontCollection,
withName: "Visible to the Current User", visibility: .User)
}
catch {
print("There was an error showing font collection. Info: \(error)")
}
To add a non-persistent font collection:
Repeat above steps, substituting .Computer with .Process:
do {
try NSFontCollection.showFontCollection(collection: NSFontCollection,
withName: "Visible for Current Process", visibility: .Process)
}
catch {
print("There was an error showing font collection. Info: \(error)")
}
Next steps…
Once you have a collection, you can change it all you want using the NSMutableFontCollection class. Continuing with the example above, you would do something like this:
let mutableCollection = collection.mutableCopy() as! NSMutableFontCollection
let boldTrait = [NSFontWeightTrait: NSFontWeightBold]
let boldAttributes = [NSFontTraitsAttribute: boldTrait]
let boldDescriptor = NSFontDescriptor(fontAttributes: newAttributes)
mutableCollection.addQueryForDescriptors([boldDescriptor])
At this point, the API gets weird again. We've added descriptors to our "named collection," but nothing in the UI is going to show up until you "show" the font collection again. In other words, after making any changes, you have to call showFontCollection(_:withName:visibility:) again.
Likewise, if you want to remove/delete a collection, you have to call hideFontCollectionWithName(_:visibility:). Despite its innocuous name, this method completely removes a persistent collection from disk, so be careful.
Next next steps…
In subsequent launches of your app, you can retrieve any persistent collection using the NSFontCollection(name:visibility:) method, like so:
// Retrieve collection created at an earlier time
let collectionOnDisk = NSFontCollection(name: "Visible to All Users", visibility: .Computer)
I think I've covered most of it, but if I've missed something, or if you have questions, just let me know. Good luck!
There are classes NSFontCollection and NSFontDescriptor.
Look into the NSFontManager header file of Xcode 7 (via ⇧⌘O) to get more information about the deprecated methods and their replacement.
Since I am fairly new to Swift programming on OSX, this question may contain several points that needs clarification.
I have a method which iterates over all subviews of a given NSView instance. For this, I get the array of subviews which is of type [AnyObject] and process one element at a time.
At some point I would like to access the identifier property of each instance. This property is implemented from a protocol in NSView named NSUserInterfaceItemIdentification, which type is given in the documentation as (optional) String?. In order to get that identifier I would have written
var view : NSView = subview as NSView;
var viewIdent : String = view.identifier!;
The second line is marked by the compiler with an error stating that identifier is not of an optional type, but instead of type String, and hence the post-fix operator ! cannot be applied.
Removing this operator compiles fine, but leads to a runtime error EXC_BAD_ACCESS (code=1, address=0x0) because identifier seems to be nil for some NSButton instance.
I cannot even test for this property, because the compiler gives me a String is not convertible to UInt8 while I try
if (view.identifier != nil) {viewIdent = view.identifier;}
My questions are
Is the documentation wrong? I.g. the property identifier is not optional?
How can I ship around this problem and get code that runs robust?
If the documentation states that view.identifier is an Optional, it means it can be nil. So it's not a surprise that for some button instances it is indeed nil for you.
Force unwrapping this element that can be nil will lead your app to crash, you can use safe unwrapping instead:
if let viewIdent = view.identifier {
// do something with viewIdent
} else {
// view.identifier was nil
}
You can easily check the type of an element in Xcode: click on the element while holding the ALT key. It will reveal a popup with informations, including the type. You can verify there that your element is an Optional or not.
Tip: you can safe unwrap several items on one line, it's rather convenient:
if let view = subview as? NSView, viewIdent = view.identifier {
// you can do something here with `viewIdent` because `view` and `view.identifier` were both not nil
} else {
// `view` or `view.identifier` was nil, handle the error here
}
EDIT:
You have to remove this line of yours before using my example:
var viewIdent : String = view.identifier!
Because if you keep this line before my examples, it won't work because you transform what was an Optional in a non-Optional by adding this exclamation mark.
Also it forces casting to a String, but maybe your identifier is an Int instead, so you shouldn't use this kind of declaration but prefer if let ... to safe unwrap and cast the value.
EDIT2:
You say my example doesn't compile... I test every answer I make on SO. I tested this one in a Playground before answering, here's a screenshot:
Also, after checking it, I confirm that the identifier is an Optional String, that's the type given by Xcode when using ALT+CLICK on the property. The documentation is right.
So if it's different for you, it means you have a different problem unrelated to this one; but my answer for this precise question remains the same.
I have some code in my Mac app that performs a long-running export operation. At the end of the export, it creates a user notification to let the user know it's finished:
- (NSUserNotification*)deliverNotificationWithSound:(NSString*)sound title:(NSString*)title messageFormat:(NSString*)message {
NSUserNotification * note = [NSUserNotification new];
note.soundName = sound;
note.title = title;
note.informativeText = [NSString stringWithFormat:message, NSRunningApplication.currentApplication.localizedName, self.document.displayName];
note.userInfo = #{ #"documentFileURL": self.document.fileURL.absoluteString };
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:note];
return note;
}
It then puts a sheet up with details about the export (warnings encountered, a handy "Reveal" button, etc.). When they dismiss the sheet, I want to remove the notification, like so:
[NSUserNotificationCenter.defaultUserNotificationCenter removeDeliveredNotification:note];
However, this doesn't actually remove the notification from Notification Center. I've set a breakpoint; the -removeDeliveredNotification: line is run, and note is not nil. What gives?
The notification you are attempting to be removed must be in the deliveredNotifications array. Quote the docs for -removeDeliveredNotification:
If the user notification is not in deliveredNotifications, nothing happens.
Your notification may be copied when you call -deliverNotification:, so keeping a reference to that instance and attempting to remove later it may fail. Instead, stash something in the notification's userInfo property so you can identify it, and scan through the deliveredNotifications array to find the notification you want to remove.
Added by Brent
Here's the corrected version of the method in my question. I'm using the original notification's pointer value, casted to an integer, to identify the copy; this isn't foolproof, but it's probably good enough.
- (NSUserNotification*)deliverNotificationWithSound:(NSString*)sound title:(NSString*)title messageFormat:(NSString*)message {
NSUserNotification * note = [NSUserNotification new];
note.soundName = sound;
note.title = title;
note.informativeText = [NSString stringWithFormat:message, NSRunningApplication.currentApplication.localizedName, self.document.displayName];
note.userInfo = #{ #"documentFileURL": self.document.fileURL.absoluteString, #"originalPointer": #((NSUInteger)note) };
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:note];
// NSUserNotificationCenter actually delivers a copy of the notification, not the original.
// If we want to remove the notification later, we'll need that copy.
for(NSUserNotification * deliveredNote in NSUserNotificationCenter.defaultUserNotificationCenter.deliveredNotifications) {
if([deliveredNote.userInfo[#"originalPointer"] isEqualToNumber:note.userInfo[#"originalPointer"]]) {
return deliveredNote;
}
}
return nil;
}
Thanks for the great question.
It seems like Apple was fixed issue because it will work for me by using the single line of code.
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: aryIdentifier)
I have tried 5-6 hours in the simulator to clear local notification but no luck. When I will run code in the actual device it will like the charm.
Happy coding.