Create PDF in Swift - ios

I am following Apple's Docs to create a PDF file using Xcode6-Beta6 in Swift
var currentText:CFAttributedStringRef = CFAttributedStringCreate(nil, textView.text as NSString, nil)
if (currentText) { // <-- This is the line XCode is not happy
// More code here
}
Compiler throws Type 'CFAttributedStringRef' does not conform to protocol 'BooleanType' error
If I use if(currentText != nil) I get 'CFAttributedStringRef' is not convertible to 'UInt8'
From Apple's Docs for CFAttributedStringCreate
Return Value
An attributed string that contains the characters from str and the attributes specified by attributes. The result is NULL if there was a problem in creating the attributed string. Ownership follows the Create Rule.
Any idea how to resolve this? Thanks!

First you have to give it an explicit optional type (using the ?):
var currentText: CFAttributedStringRef? = ...
Then you can compare it to nil:
if currentText != nil {
// good to go
}
Your code compiles at the moment, because Apple hasn't yet "swiftified" CoreFoundation to return properly annotated types.
Be prepared that in the final release your code will not even compile, forcing you to use the optional type.

Related

Binary operator cannot be applied to operands of type Int and String - Swift 2.3 -> Swift 3.2 conversion error

While converting from Swift 2.3 to 3.2 I received below error.
Error : Binary operator cannot be applied to operands of type Int and String
for this if Condition i.e if (error?.code)! == "-112" which is shown in below line.
if (error?.code)! == "-112"
{
print("hello")
}
Error itself says it's different types Int and String.
You can need to typecast one or another in same form and them compare.
if (String(error?.code)!) == "-112"){
print("hello")
}
Swift is a language with a strong type system. You can compare only values of the same type.
Since the left side is Int anyway use an Int value for the right side. Creating a string is unnecessarily expensive. Don’t do that.
The most efficient (and safe) solution is
if error?.code == -112
{
print("hello")
}
You need to type-cast your error code result to a string, like so:
if String(error?.code)!) == "-112" {
print("Hello")
}
Essentially, you are taking the error?.code, "casting" it as a string by placing it in a string "container mould" and unwrapping the value (retrieving the casted result).
In addition, if you are working with an API response, you have to account for all other error codes in the else/if statement to make sure all responses are handled properly (just in case you are).

Cannot convert value of type String to specified type NSManagedObjectContext, While converting from Swift 2.3 -> 3.2

I need Help. While conversion from Swift 2.3 -> 3.2 I received below error. I'm not able to resolve this error.
Below is my coding stuff, where I'm facing some issues.
Error1 : Cannot convert value of type String to specified type
NSManagedObjectContext**
Error2 : Cannot convert return expression of type URL to return type URL.
class func persistentFileURL(_ name: String, enclosingDirectoryName: String) -> Foundation.URL {
let directoryURL = self.directoryForPersistentStorage(enclosingDirectoryName)
let urlPath = directoryURL.path
let filePath: NSManagedObjectContext = (urlPath as NSString).appendingPathComponent(name) //Error1 : Cannot convert value of type String to specified type NSManagedObjectContext
return URL(context: filePath) // Error2 : Cannot convert return expression of type URL to return type URL.
}
Note : URL is separate Class declared to handle this : URL_Class
Please help me. I'm very new to iOS. Not able to understand this type of error.
let filePath: NSManagedObjectContext = (urlPath as NSString).appendingPathComponent(name)
should read
let filePath: String = (urlPath as NSString).appendingPathComponent(name)
Error 2:
URL doesn't have any constructor using context:. Try to use init(fileURLWithPath:) instead (which expects a string, so you need to make filePath an instance of string instead of an NSManagedObject).
See official docs on URL from Apple here.
EDIT
Seeing as you are returning a custom URL object (subclass of NSManagedObject), you need to change the return type of your function.
From -> Foundation.URL to -> URL. I'd suggest to rename your custom URL subclass to something else, since this name is already used by Apple and will probably cause some namespace issues (compiler will get confused and you will get errors).

Cannot assign value of type 'String?' to type 'Int'

I am getting the error message Cannot assign value of type 'String?' to type 'Int'
I have browsed through other questions like this but it still shows the error.
if sunscreenName.text != nil && reapplyTime.text != nil {
sunscreen = sunscreenName.text!
reApplyTime = reapplyTime.text
//Some sort of message such as Progress hud
}
Thanks in advance!
I got your problem, actually what happens here Swift is is type safe langauge
So what you are doing is is to store a String value in Int which will not happen automatically you need to convert it to Int
like this
Int(sunscreenName.text)
But there is a catch there not all string are convertible to Int type, fo e.g.
let name = "roshan"
if you try to convert it to Int it will give you a nil
let a = Int(name)
So its better you do a optional Binding here provided by Swift
if let sunValue = Int(sunscreenName.text),let reApplyValue = Int(reapplyTime.text) {
sunscreen = sunValue
reApplyTime = reApplyValue
}
I recommend reading through The Swift Programming Language to get a better understanding of Swift and its fundamental concepts, since this question is fairly basic.
You make several mistakes:
if sunscreenName.text != nil && reapplyTime.text != nil {
This is wrong. In Swift, if you plan to use the value later, you should use if let rather than comparing to nil. Comparing to nil leaves the values optional, but if let unwraps them. So, do this instead:
if let sunscreenText = sunscreenName.text, let reapplyText = reapplyTime.text {
Now you have the sunscreenText and reapplyText variables, which are typed String, not String? (i.e. they are not optional).
Now, there's these two lines.
sunscreen = sunscreenName.text!
reApplyTime = reapplyTime.text
You don't say which one is giving the error, but the issue is the same in either case. First, use our unwrapped sunscreenText and reapplyText variables instead of sunscreenName.text! and reapplyTime.text. Next, if one of these is meant to be an Int instead of a String, cast it. Swift is not like JavaScript, in that it won't automatically convert values from one type to another, so if something is a string and we need an integer, we have to convert it ourselves.
(assuming reapplyTime was the line that was giving the error:)
if let reapplyInt = Int(reapplyText) {
reapplyTime = reapplyInt
}
The reason we have to unwrap is because Int(String) can return nil if the string is something that can't be converted to an integer. Alternately, we could just provide a default value:
reapplyTime = Int(reapplyText) ?? 0 // sets to 0 if it can't parse the string as an integer

Swift cannot assign value of type '()' to type 'String?'

I'm learning Swift2/iOS app development. I am confused by an error being thrown by Xcode before compiling. Here is the code throwing the error :
let dotpos = display.text!.rangeOfString(".")
if dotpos != nil {
display.text = display.text!.removeRange(dotpos!)
}
The error thrown is (at the line "display.text = display.text!.removeRange(dotpos!)") :
Cannot assign value of type '()' to type 'String?'
Note : display is a UILabel object.
Could someone point me toward the error I might have done?
you need to check documentation for this (Apple swift String link)
let dotpos = display.text!.rangeOfString(".")
if dotpos != nil {
display.text!.removeRange(dotpos!)
}
This code will work, removeRange function didn't return anything, documentation said
mutating func removeRange(_ subRange: Range)
means text mutate when you call the method on your text label.
The text change directly and you don't need to assign new value for changing it.

Insert a potentially null value into the sqlite database in iOS

I have a class called Content, whose URL property is nullable (URL: String?).
I'd like to store this URL property in my sqlite database using FMDB, but Xcode complains I need to unwrap the optional with !
but the problem is when I do content.URL! it crashes because it's nil.
success = db.executeUpdate("INSERT INTO CONTENT(ID, Icon, Title, Description, URL, IsActive) VALUES(?,?,?,?,?,?,?,?,?)", withArgumentsInArray: [content.ID, content.icon, content.title, content.description, content.URL!, content.isActive])
How can I successfully insert URL both when it has and does not have a value?
Thanks!
One approach that I use for cases like this is to create a class extension.
For example:
class func databaseSafeObject(object: AnyObject?) -> AnyObject {
if let safeObject: AnyObject = object{
return safeObject;
}
return NSNull();
}
Then you can just use:
NSObject.databaseSafeObject(content.URL);
to get something that can be directly inserted in the db.
So this ended up working for me, although it seems kinda irking that this is how it has to be:
(content.URL == nil ? NSNull() : content.URL!)
There exists Swift wrappers for SQLite that may be a better fit that fmdb which can run in Swift but does not use Swift features such as optionals (that you miss here), type safety, and error handling. See for example my GRDB.swift http://github.com/groue/GRDB.swift which was heavily influenced by ccgus/fmdb.
The AnyObject type didn't work for me when working with variables of type Int and Double, so I created a similar function to handle optional Swift variables.
private func getOptionalOrNull(_ possibleValue:Any?)->Any {
if let theValue = possibleValue {
return theValue
} else {
return NSNull()
}
}

Resources