This is from debug.
url String "https://openweathermap.org/img/w/Optional(\50n\).png"
The problem is in this line:
self.imgURL = "https://openweathermap.org/img/w/\(self.dodatek).png"
When I change (self.dodatek) for example to icon 50n it works and show me the icon.
When I start my weather app and write name of the city I want to have url like this, but for 50n it has to be my variable that is taken from json.
https://openweathermap.org/img/w/50n.png
Looks like the quick and dirty fix for your problem is unwrapping the optional dodatek(which is probably String?) like this
self.imgURL = "https://openweathermap.org/img/w/\(self.dodatek!).png"
The cleaner solution is definitely
guard let dodatek = self.dodatek else {
// handle that dodatek is nil
// or just return
return
}
self.imgURL = "https://openweathermap.org/img/w/\(dodatek).png"
Explanation
The problem is that your property dodatek can theoretically be nil when you declare it as String?
If you are sure that it can never be nil, declare it as
var dodatek: String // not String?
instead.
In case it can be nil, the guard let statement above should be used to either define a fallback value of an url that should be used (like a url to a generic weather icon maybe)
Related
I tried for a long time to turn the text into an Int but it did not work. I tried it like this:
(AnzahlString is a textfield)
var AnzahlAInt = 0
if let AnzahlAString = AnzahlString.text {
let AnzahlAInt = Int(AnzahlAString)
}
But then I always get the error:
Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
Then I added a ! at the end of Int(AnzahlAString)! so I don't get a error, but now when I press on the button, the app crashes. It was predictable, but how can I change this now to an Int without the !?
At first glance, it looks like you have two things to check for:
is AnzahlString.text present, and
does it represent an Int
The first check is in fact not necessary, since .text will never return nil, even though it's marked as Optional. This means you can safely force-unwrap it.
The second check is easily done by using the ?? operator:
let AnzahlAInt = Int(AnzahlString.text!) ?? 0
PS, just as a stylistic hint: variable names in Swift ususally start with a lowercase letter, names starting with capital letters are used for types.
PPS: your code as written shadows AnzahlAInt - the value of your var is never changed.
The reason why the resulting Int is optional, is that parsing might or might not succeed. For example, if you try to parse the string "Fluffy Bunnies" into an Int, there is no reasonable Int that can be returned, therefore the result of parsing that string will be nil.
Furthermore, if you force the parser by using !, you're telling Swift that you know for sure that the string you pass will always result in a valid Int, and when it doesn't, the app crashes.
You need to handle the situation in which the parse result is nil. For example:
if let AnzahlAIntResult = Int(AnzahlAString) {
// We only get here if the parse was successful and we have an Int.
// AnzahlAIntResult is now an Int, so it can be assigned to AnzahlAInt.
AnzahlAInt = AnzahlAIntResult
}
You did a good job so far but missed out one thing.
This line tries to convert the String into an Int. However this can fail, since your String can be something like this "dfhuse".
let AnzahlAInt = Int(AnzahlAString)
This is why the result of Int(AnzahlAString) is an Optional (Int?). To use it as an real Int, you have to unwrap it.
First solution is the !, however, every time this does fail your app crashes. Not a good Idea to use so.
The best solution would be Optional Binding, as you already used to get the text of your text field.
if let AnzahlAString = AnzahlString.text {
if let safeInt = Int(AnzahlAString) {
// You can use safeInt as a real Int
} else {
print("Converting your String to an Int failed badly!")
}
}
Hope this helps you. Feel free to ask again if something is unclear.
For unwrapping you can also use guard like this
Simple and easy
guard let AnzahlAInt = Int(AnzahlString.text!) else {
return
}
print(AnzahlAInt)
This is a fairly specific situation, so I'll try to explain as many details as possible.
I'm making an app that should fetch a list of reservations, where it's possible to either add new, or tap an existing reservation and have a "detailed" view about the reservation where the reservation details are editable, and then have an option to save it.
REST APIs have been done in C#, and there's no documentation on what can and can't be null (nil, in Swift case). So I'm ending up with:
struct Reservation: Codable {
var objectID: String?
var objectName: String?
var objectPrefix: String?
var reservationNumber: String?
var grownUPS: Int?
var teens: Int?
var children: Int?
var babies: Int?
var reservationDate: String?
var dateInserted: String?
var toDate:String?
var fromDate: String?
var price: Int?
var owner: String?
var note: String?
var agencyName: String?
var renterNote: String?
var reservationID: String?
// 20 more properties
init(objectID: String? = nil,
partnerID: String? = nil,
objectName: String? = nil,
// 20 more properties
)
{
self.objectID = objectID
self.objectName = objectName
// 20 more properties
}
So when I tap on an object, I pass a Reservation object, check every field, if not nil then set to TextField. On clicking save I update model from all TextFields, DatePickers, etc, and then do a network post or put request depending on whether it's a new reservation or editing existing.
If I tap on add, I pass an empty Reservation object, so all fields on "details" page are empty, and do a validation when clicking Save button.
It works so far, but all around it looks "Anti-Swift". Lot of optionals, lot of guards/unwrapping, tight coupling between "master" and "details" view, setting data retrieved from network in a closure (actual Alamofire call is hidden, but I'm not sure what will be nil, so I have to set each property to it's TextField with a nil-check/chaining).
Any arhitecture tips on how to improve this?
All tutorials on this make a simple, local, non-optional approach that makes everything look shiny.
Keep in mind I've no documentation what is allowed to be null (data previously entered via web, or internal desktop app).
One thing that I can think of from the top of my head would be to remove the optionality of some properties by defining default values eg var babies: Int = 0 or if you're using Swift's decodable you can do something like this
babies = (try? container.decode(Int.self, forKey: .babies)) ?? 0
so you don't have to make your babies variable an optional
edit based on comment: the ?? aka coalescing nil operator will try to unwrap the optional value on the left and if it is nil, it will return the value on the right which in this case is 0
I don't think you should be bothered by optionals and optionals unwrapping.
One of the powers of optionals is, that anybody who works with your code, knows, that this thing may take nil as its value.
Unwrapping logic, either you use guards , nil coalescing or any other unwrapping technique describes your business logic. The fact, that you have "big" model is, IMO, just a fact that should be accepted. It's ok until your code stays reliable, readable, testable and understandable, doesn't cause unnecessary side effects and so on.
You might "fix" this problem by adding another level of abstraction over unwrapping or so. But, IMO, it should be done very carefully and only for the case of real benefits.
SwiftyJson solves exactly what you are facing. Its great in handling optional chaining and unwrapping of a great no of objects very efficiently and in a very Swifty way.
If some type conversion fails it doesn't break but gives an empty value so that your app works without you checking every single variable.
Here is basic conversion example provided. For details please go through their documentation.
// Getting a double from a JSON Array
let name = json[0].double
// Getting an array of string from a JSON Array
let arrayNames = json["users"].arrayValue.map({$0["name"].stringValue})
// Getting a string from a JSON Dictionary
let name = json["name"].stringValue
// Getting a string using a path to the element
let path: [JSONSubscriptType] = [1,"list",2,"name"]
let name = json[path].string
// Just the same
let name = json[1]["list"][2]["name"].string
// Alternatively
let name = json[1,"list",2,"name"].string
Originally I tried to use something like this:
extension URL: CustomStringConvertible{
public override var description: String {
let url = self
return url.path.removingPercentEncoding ?? ""
}
}
After fixing compiler warning code became:
extension URL{
public var description: String {
let url = self
return url.path.removingPercentEncoding ?? ""
}
}
but
print(fileURL) still shows old URL description with percentages.
You can't override a method in an extension. What you're trying to do isn't possible in Swift. It's possible in ObjC (on NSURL) by swizzling the methods, but this should never be done in production code. Even if you could get the above working in Swift through some trickery, you should never use that in production code for the same reason. It could easily impact you in very surprising ways (for instance, it could break NSCoding implementations that expect description to work a certain way.
If you want this style of string, create a method for it and call that when you want it. Don't modify description in an existing class.
I have a NSObject Subclass. Say CityWalks
class CityWalks{
var totalCount:Int?
}
How do I use this property further? Should I check the nil coalescing every time this value is accessed.
example:
let aObject =
say in one fucntion (function1()) , I need to access this value, then it would like (aObject!.totalCount ?? 0)
func function1(){
...Some Access code for the object....
(aObject!.totalCount ?? 0)
}
Similarly in every other function(function2()) , I will have to write the same code.
func function2(){
...Some Access code for the object....
(aObject!.totalCount ?? 0)
}
So, what could be a better approach for such field, considering this property might receive a value from server or might not.
If you have a default value for this property just assign this value as default value.
class YourClass {
var totalCount = 0
}
I'd recommend you avoid using an optional value if it's possible. Because optional values its a first place when you can get an error.
As stated in the comments and the other answer using an optional is not really optimal in your case. It seems like you might as well use a default value of 0.
However, to clarify, you have to check the value when unwrapping the optional.
Sometimes it's possible to pass an optional to UIElement etc and then you don't really need to do anything with them
There are pretty ways of checking for nil in optional values built into swift so you can build pretty neat code even though you work with optional.
Look in to guard let and if let if you want to know more about unwrapping values safely.
if let
if let totalWalks = aObject?.totalCount {
//operate on totalWalks
}
guard
guard let totalWalks = aObject?.totalCount else { return }
//operate on totalWalks
There are also cases where you will want to call a function on an optional value and in this case you can do so with ?
aObject?.doSomething()
Any return values this function might have will now be wrapped in an optional and you might have to unwrap them as well with an if let or guard
When working with optionals you should try to avoid forcing the unwrap with ! as even though you at the moment know that the value is not null that might after a change in the code not be true anymore.
I have a field stored on a core data object called "metadata" which is of type String (no optional, because Apple docs say not to mess with optionals in CD). Sometimes, the metadata field is nil. In checking whether this value is nil, I do the following check:
if object.metadata as String? != nil {
...
}
However, my code continuously crashes on this line as an EXC_BAD_ACCESS. I have also tried:
if let metadata = object.metadata as String? {
...
}
Which doesn't work either. I cast objects successfully to optionals in other parts of my code, so I don't understand why this particular case isn't working. How do you check whether a core data property is a nil string?
It looks like what you really want is this:
if object.metadata != nil {
...
}
or this:
if let metadata = object.metadata as? String {
// You can now freely access metadata as a non-optional
...
}
--EDIT--
My mistake, I didn't read the first part of your question thoroughly enough. It looks like the duplicate answer has a solution for this. Essentially, the generated managed object subclass is a bug and you should modify the properties to be either optional or implicitly unwrapped. You can check both of those using the first method for implicitly unwrapped and second for optionals.
There are several questions which discuss the issue of the generated subclasses not producing optional properties. I wouldn't be too concerned about editing the subclasses; there's nothing special about them except that Apple is making it easier to create them.
Check if property is set in Core Data?
Swift + CoreData: Cannot Automatically Set Optional Attribute On Generated NSManagedObject Subclass
--Edit2--
If you really don't want to touch the subclass you can access the property using valueForKey() and could add that as an extension if you wanted something a bit cleaner.
if let metadata = object.valueForKey("metadata") as String? {
...
}
In an extension:
extension ObjectClass {
var realMetadata: String? {
set {
self.setValue(newValue, forKey: "metadata")
}
get {
return self.valueForKey("metadata") as String?
}
}
}