I have a instance variable name in String
var name: String
My class implements the NSCoding protocol. So for name I had
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.name, forKey: kName)
}
required init(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey(kName) as String // CRASH HERE
}
Result? I was getting a run time crash during initiation with decoder. I changed init to this:
var temp = aDecoder.decodeObjectForKey(kName) as NSString!
self.name = aDecoder.decodeObjectForKey(kName) as String
and realised the value temp is holding the right NSString value. so I thought the line below is going to fix it but it issues a linker error:
self.name = aDecoder.decodeObjectForKey(kName) as NSString!
the questions is how to take the temp and put it into name?
decodeObjectForKey returns an optional AnyObject?, so you have to guard your code against possible nil values. Using a cast to a forced unwrapped doesn't sound safe.
I am unable to reproduce the error (so the problem could be somewhere else in your code), but this is how I would approach when initializing the name property:
var tempName = aDecoder.decodeObjectForKey("name") as? String
if let tempName = tempName {
self.name = tempName
} else {
self.name = "some initial value"
}
Note the usage of the optional downcasting as?, which always produce a result (nil or a valid type value) as opposed to as NSString!, which triggers an exception if the downcast is not possible (for instance if you are expecting a string, but it's an int instead).
That code would also allow you to better debugging - if tempName is nil, then either the key doesn't exist or the corresponding value is of a different type.
There were two things I needed to do to get it working:
clean build with removing the derived data folder
For some reason bridging between the NSString and String is not working in this situation. so the casting should be done in two stages
if let name = aDecoder.decodeObjectForKey(kName) as? NSString {
self.name = name as String
} else {
assert(false, "ERROR: could not decode")
self.name = "ERROR"
}
Related
I'm learning basic kotlin in these days.
class Human (val name : String = "Anonymous") {
fun drinkingCoffee() {
println("this is so good")
}
}
fun main() {
var human = Human(name: "jinhwa") // error is here.
human.drinkingCoffee()
println("this is human's name is ${human.name}")
}
android studio said Expecting ')', but I can't find out why this isn't work
So basically you messed up with a colon while calling Human(). A colon is used to specify type like var x: String = "" when you're using named arguments you do name = value
Reference: kotlin documentation, kotlin by example
Full code:
class Human(val name: String = "Anonymous") {
fun drinkingCoffee() {
println("this is so good")
}
}
fun main() {
var human = Human(name = "jinhwa") // error is here.
human.drinkingCoffee()
println("this is human's name is ${human.name}")
}
The problem here is an invalid part of the argument to the constructor of your class Human.
tl;dr
This is wrong: Human(name : "jinhwa")
This is correct: Human(name = "jinhwa")
You don't have to give the name of a specific argument when calling the constructor, especially when there is only a single one, but you can do it.
If you do it, write an equality sign where you have written a colon in your code.
Valid constructor calls in your scenario are
a call without passing a parameter: Human()
a call with a parameter value but no parameter name: Human("jinhwa")
a call with a parameter name and value: Human(name = "jinhwa")
So the following code that uses your class Human...
fun main() {
var defaultConstructedHuman = Human()
var withparamNameConstructedHuman = Human(name = "jinhwa")
var withoutParamNameConstructedHuman = Human("Arthur")
println("this human's name is ${defaultConstructedHuman.name}")
println("this human's name is ${withparamNameConstructedHuman.name}")
println("this human's name is ${withoutParamNameConstructedHuman.name}")
}
and the code will run.
It will also run if you create a Human without passing a name, the result would be an Anonymous one:
fun main() {
var human = Human() // nothing passed, "name" takes the default value "Anonymous"
human.drinkingCoffee()
println("this is human's name is ${human.name}")
}
... will compile and output
this human's name is Anonymous
this human's name is jinhwa
this human's name is Arthur
I want to user sting in another class so if you know how to use? please help me.
I am using below link but it did't work for me. it return nil or fatal error.
How to call another method from another class in swift?
below code:
var objSymbol = SymbolListVC()
code = objSymbol.code
selectedMarket = objSymbol.SMarket
below Code of Symbol class:I am gating the value in code and skt
var Skt: String!
var code: String!
code = sbol?["Code"] as? String
Skt = sbol?["kt"] as? String
Thank You.
Does SymbolListVC.code have an initial value? Or do you mean to use an existing object of SymbolListVC and read the value of code from there?
Ideally, you should be using if directives if you are not certain that a variable will have a value
if let code = objSymbol.code {
//Do your processing here
}
But before that, assuming you want to use an existing instance of SymbolListVC, your code will create a new object of the class. So you might want to change that part.
var valueToPass:String!
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel.text
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "yourSegueIdentifer") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as AnotherViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}
I would like to replace my global string constants with a nested enum for the keys I'm using to access columns in a database.
The structure is as follows:
enum DatabaseKeys {
enum User: String {
case Table = "User"
case Username = "username"
...
}
...
}
Each table in the database is an inner enum, with the name of the table being the enum's title. The first case in each enum will be the name of the table, and the following cases are the columns in its table.
To use this, it's pretty simple:
myUser[DatabaseKeys.User.Username.rawValue] = "Johnny"
But I will be using these enums a lot. Having to append .rawValue to every instance will be a pain, and it's not as readable as I'd like it to be. How can I access the String value without having to use rawValue? It'd be great if I can do this:
myUser[DatabaseKeys.User.Username] = "Johnny"
Note that I'm using Swift 2. If there's an even better way to accomplish this I'd love to hear it!
While I didn't find a way to do this using the desired syntax with enums, this is possible using structs.
struct DatabaseKeys {
struct User {
static let identifier = "User"
static let Username = "username"
}
}
To use:
myUser[DatabaseKeys.User.Username] = "Johnny"
Apple uses structs like this for storyboard and row type identifiers in the WatchKit templates.
You can use CustomStringConvertible protocol for this.
From documentation,
String(instance) will work for an instance of any type, returning its
description if the instance happens to be CustomStringConvertible.
Using CustomStringConvertible as a generic constraint, or accessing a
conforming type's description directly, is therefore discouraged.
So, if you conform to this protocol and return your rawValue through the description method, you will be able to use String(Table.User) to get the value.
enum User: String, CustomStringConvertible {
case Table = "User"
case Username = "username"
var description: String {
return self.rawValue
}
}
var myUser = [String: String]()
myUser[String(DatabaseKeys.User.Username)] = "Johnny"
print(myUser) // ["username": "Johnny"]
You can use callAsFunction (New in Swift 5.2) on your enum that conforms to String.
enum KeychainKey: String {
case userId
case email
}
func callAsFunction() -> String {
return self.rawValue
}
usage:
KeychainKey.userId()
You can do this with custom class:
enum Names: String {
case something, thing
}
class CustomData {
subscript(key: Names) -> Any? {
get {
return self.customData[key.rawValue]
}
set(newValue) {
self.customData[key.rawValue] = newValue
}
}
private var customData = [String: Any]()
}
...
let cData = CustomData()
cData[Names.thing] = 56
Edit:
I found an another solution, that working with Swift 3:
enum CustomKey: String {
case one, two, three
}
extension Dictionary where Key: ExpressibleByStringLiteral {
subscript(key: CustomKey) -> Value? {
get {
return self[key.rawValue as! Key]
}
set {
self[key.rawValue as! Key] = newValue
}
}
}
var dict: [String: Any] = [:]
dict[CustomKey.one] = 1
dict["two"] = true
dict[.three] = 3
print(dict["one"]!)
print(dict[CustomKey.two]!)
print(dict[.three]!)
If you are able to use User as dictionary key instead of String (User is Hashable by default) it would be a solution.
If not you should use yours with a nested struct and static variables/constants.
If I declared a String like this: var date = String()
and I want to check if it is a nil String or not,
so that I try something like:
if date != nil{
println("It's not nil")
}
But I got an error like : Can not invoke '!=' with an argument list of type '(#lvalue String, NilLiteralConvertible)'
after that I try this:
if let date1 = date {
println("It's not nil")
}
But still getting an error like:
Bound value in a conditional binding must be of Optional type
So my question is how can I check that the String is not nil if I declare it this way?
The string can't be nil. That's the point of this sort of typing in Swift.
If you want it to be possibly nil, declare it as an optional:
var date : String?
If you want to check a string is empty (don't do this, it's the sort of thing optionals were made to work around) then:
if date.isEmpty
But you really should be using optionals.
You may try this...
var date : String!
...
if let dateExists = date {
// Use the existing value from dateExists inside here.
}
Happy Coding!!!
In your example the string cannot be nil. To declare a string which can accept nil you have to declare optional string:
var date: String? = String()
After that declaration your tests will be fine and you could assign nil to that variable.
Its a bit late but might help others. You can create an optional string extension. I did the following to set an optional string to empty if it was nil :
extension Optional where Wrapped == String {
mutating func setToEmptyIfNil() {
guard self != nil else {
self = ""
return
}
}
}
I want to make an Int from an String, but can't find how to.
This is my func:
func setAttributesFromDictionary(aDictionary: Dictionary<String, String>) {
self.appId = aDictionary["id"].toInt()
self.title = aDictionary["title"] as String
self.developer = aDictionary["developer"] as String
self.imageUrl = aDictionary["imageUrl"] as String
self.url = aDictionary["url"] as String
self.content = aDictionary["content"] as String
}
When using toInt() I get the error messag Could not find member 'toInt'. I can't use Int(aDictionary["id"]) either.
Subscripting a dictionary, with the dict[key] method, always returns an optional. For example, if your dictionary is Dictionary<String,String> then subscript will return an object with type String?. Thus the error that you are seeing of "Could not find member 'toInt()'" occurs because String?, an optional, does not support toInt(). But, String does.
You may also note that toInt() returns Int?, an optional.
The recommended approach to your need is something along the lines of:
func setAttributesFromDictionary(aDictionary: Dictionary<String, String>) {
if let value = aDictionary["id"]?.toInt() {
self.appId = value
}
// ...
}
The assignment will occur iff aDictionary has an id mapping and its value is convertible to an Int.
In action: