Since Swift 2.0 ] get the following error executing this line of code in my GameViewController:
var sceneData = NSData(contentsOfFile: path, options: .DataReadingMappedIfSafe, error: nil)!
ERROR: "Type of expression is ambiguous without more context"
Replace with
NSDataReadingOptions.DataReadingMappedIfSafe
and remove last parameter:
NSData(contentsOfFile: path, options: NSDataReadingOptions.DataReadingMappedIfSafe)
the call can throw and exception, enclose your call in
do {
let data = try NSData(contentsOfFile: path, options:NSDataReadingOptions.DataReadingMappedIfSafe)
}catch {
print("Error")
}
Related
I am rewriting a project I found on Github to learn and teach myself how to use swift and pod files. I upgraded Kanna from 2.2.1 to 4.0.2 because I was getting an arm64 error.
With 4.0.2 I am getting the error:
Initializer for conditional binding must have Optional type, not 'HTMLDocument'
Call can throw, but it is not marked with 'try' and the error is not handled
I am unsure about what this error means and how to fix it. It is associated with this if statement:
if let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
}
The type signature for the method you are calling is public func HTML(html: String, url: String? = nil, encoding: String.Encoding, option: ParseOption = kDefaultHtmlParseOption) throws -> HTMLDocument. The function returns a non-Optional value, but can throw an error.
You can handle the error by either using the try? keyword to make the function return nil in case an error was thrown and make the optional binding you currently use work like this:
if let doc = try? Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {...
or rather use try and put the function call in a do-catch block to see the actual error in case any was thrown.
do {
let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8)
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
} catch {
print(error)
// Handle error
}
I'm migrating my code over to Swift 3 and see a bunch of the same warnings with my do/try/catch blocks. I want to check if an assignment doesn't return nil and then print something out to the console if it doesn't work. The catch block says it "is unreachable because no errors are thrown in 'do' block". I would want to catch all errors with one catch block.
let xmlString: String?
do{
//Warning for line below: "no calls to throwing function occurs within 'try' expression
try xmlString = String(contentsOfURL: accessURL, encoding: String.Encoding.utf8)
var xmlDict = XMLDictionaryParser.sharedInstance().dictionary(with: xmlString)
if let models = xmlDict?["Cygnet"] {
self.cygnets = models as! NSArray
}
//Warning for line below: "catch block is unreachable because no errors are thrown in 'do' block
} catch {
print("error getting xml string")
}
How would I write a proper try catch block that would handle assignment errors?
One way you can do is throwing your own errors on finding nil.
With having this sort of your own error:
enum MyError: Error {
case FoundNil(String)
}
You can write something like this:
do{
let xmlString = try String(contentsOf: accessURL, encoding: String.Encoding.utf8)
guard let xmlDict = XMLDictionaryParser.sharedInstance().dictionary(with: xmlString) else {
throw MyError.FoundNil("xmlDict")
}
guard let models = xmlDict["Cygnet"] as? NSArray else {
throw MyError.FoundNil("models")
}
self.cygnets = models
} catch {
print("error getting xml string: \(error)")
}
I have code I've been using for SwiftyJSON and I'm trying to update to Swift 3 using XCode 8.0 Beta 3. I'm running into an issue where the compiler doesn't like the argument 'error: &err' as it did before. I've been searching for how to correctly pass an NSErrorPointer but everything I've found says to re-write, leave out the error and throw an error back. Since this isn't my code I'd rather leave it as it is. So what's the correct new way to use an NSErrorPointer?
var err : NSError?
// code to get jsonData from file
let json = JSON(data: jsonData, options: JSONSerialization.ReadingOptions.allowFragments, error: &err)
if err != nil {
// do something with the error
} else {
return json
}
The code above results in compiler error: '&' can only appear immediately in a call argument list. I've tried creating an NSErrorPointer so I can use that instead but I can't find anything on how to initialize one (the type alias declaration is not enough). I've already been to Using Swift with Cocoa and Obj-C, it does not contain the word NSErrorPointer, instead goes over the new way of throwing errors. I've also looked over a couple dozen posts all using the &err so apparently this is new to Swift 3.
Is there anyone out there that's solved this one? What's the answer to using NSErrorPointer?
Thanks,
Mike
That seems to be an error in the Swift 3 branch of SwiftyJSON at
https://github.com/SwiftyJSON/SwiftyJSON/blob/swift3/Source/SwiftyJSON.swift
which defines the init method as
public init(data:Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer? = nil) {
do {
let object: AnyObject = try JSONSerialization.jsonObject(with: data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error??.pointee = aError
}
self.init(NSNull())
}
}
In the Swift 3 that comes with Xcode 8 beta 3, NSErrorPointer is an optional:
public typealias NSErrorPointer = AutoreleasingUnsafeMutablePointer<NSError?>?
as a consequence of
SE-0055: Make unsafe pointer nullability explicit using Optional
Therefore the error parameter should have the type NSErrorPointer,
not NSErrorPointer? (and consequently error??.pointee
changed to error?.pointee).
With these changes the init method becomes
public init(data:Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer = nil) {
do {
let object: AnyObject = try JSONSerialization.jsonObject(with: data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error?.pointee = aError
}
self.init(NSNull())
}
}
and then your code compiles and runs as expected.
I am trying to use the countForFetchRequest method on a managed object context in Swift 2.0.
I note that the error handling for executeFetchRequest has been changed across to the new do-try-catch syntax:
func executeFetchRequest(_ request: NSFetchRequest) throws -> [AnyObject]
but the countForFetchRequest method still uses the legacy error pointer:
func countForFetchRequest(_ request: NSFetchRequest,
error error: NSErrorPointer) -> Int
...and I am having a bit of trouble figuring out how to use this in Swift 2.0.
If I do the same thing as pre-Swift 2.0:
let error: NSError? = nil
let count = managedObjectContext.countForFetchRequest(fetchRequest, error: &error)
I get errors saying to remove the &, but if I remove that I get another error saying that NSError cannot be converted to an NSErrorPointer.
Any help would be appreciated about how to get this working.
Your code is almost correct, but error needs to be a variable, in order to be passed as
inout-argument with &:
var error: NSError? = nil
let count = managedObjectContext.countForFetchRequest(fetchRequest, error: &error)
Update: As of Swift 3, countForFetchRequest
throws an error:
do {
let count = try managedObjectContext.context.count(for:fetchRequest)
return count
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
return 0
}
You need to do like this:
let error = NSErrorPointer()
let fetchResults = coreDataStack.context.countForFetchRequest(fetchRequest, error: error)
print("Count \(fetchResults)")
This is the code for Swift 2.0
Appending the .txt file component to the URL path doesn't work:
var error:NSError?
let manager = NSFileManager.defaultManager()
let docURL = manager.URLForDirectory(.DocumentDirectory, inDomain:.UserDomainMask, appropriateForURL:nil, create:true, error:&error)
docURL.URLByAppendingPathComponent("/RicFile.txt") <-- doesn't work
via debugger:
file:///Users/Ric/Library/Developer/CoreSimulator/Devices/
<device id>/data/Containers/Data/Application/<app id>/Documents/
Writing a String using docURL to a file doesn't work because of the missing file name.
Reason (via error):
"The operation couldn’t be completed. Is a directory"
So Question: Why doesn't the following work?
docURL.URLByAppendingPathComponent("/RicFile.txt")
URLByAppendingPathComponent: doesn't mutate the existing NSURL, it creates a new one. From the documentation:
URLByAppendingPathComponent: Returns a new URL made by appending a
path component to the original URL.
You'll need to assign the return value of the method to something. For example:
let directoryURL = manager.URLForDirectory(.DocumentDirectory, inDomain:.UserDomainMask, appropriateForURL:nil, create:true, error:&error)
let docURL = directoryURL.URLByAppendingPathComponent("/RicFile.txt")
Even better would be to use NSURL(string:String, relativeTo:NSURL):
let docURL = NSURL(string:"RicFile.txt", relativeTo:directoryURL)
With the update to the Swift language, the suggested call to manager.URLForDirectory(...) no longer works because the call can throw (an exception). The specific error is "Call can throw, but it is not marked with 'try' and the error is not handled". The throw can be handled with the following code:
let directoryURL: NSURL?
do
{
directoryURL = try manager.URLForDirectory(.DocumentationDirectory,
inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
}
catch _
{
print("Error: call to manager.URLForDirectory(...) threw an exception")
}