Unclear initialiser error [duplicate] - swift

This question already has answers here:
Variable used before being initialized in function
(6 answers)
Closed 5 years ago.
I have this code :
public class Foo {
init?() {
do {
let sd = FileManager.default.temporaryDirectory.appendingPathComponent("bar")
let ressourceValues = try sd.resourceValues(forKeys: [.isDirectoryKey])
if let isDirectory = ressourceValues.isDirectory {
if isDirectory {
self.something = sd
} else {
return nil
}
} else {
try FileManager.default.createDirectory(atPath: sd.path, withIntermediateDirectories: false, attributes: nil)
}
} catch {
return nil
}
}
public static let `default`: Foo? = Foo()
var something: URL
}
I get this error on the init? line:
Variable 'self.something' used before being initialized
And yet I don't see any place where I am using it in the initialiser.
What's wrong ?
Thank you

Since something isn't optional you must initialize it with a non-nil value. Your init may succeed without initializing something.

Related

Swift: HEREMaps geocoding sharedSdkEngineNotInstantiated error being thrown

So I'm using the HERE iOS SDK. For some reason, the try block isn't working, I keep getting the error printing out that is 'sharedSdkEngineNotInstantiated'. The getCoordinates function is what I'm trying to test after instantiation--I included it so that you guys aren't left guessing what the end goal is. Thanks for any and all help!
class functions: NSObject, ObservableObject {
var searchEngine: SearchEngine?
override init() {
do {
try searchEngine = SearchEngine()
} catch let engineInstantiationError {
print("Failed to make the search engine. The cause was \(engineInstantiationError)")
}
}
func getCoordinates5(from address: String) {
guard searchEngine != nil else {
return
}
let searchOptions = SearchOptions(maxItems: 10)
let query = TextQuery(address, near: GeoCoordinates(latitude: 40.7128, longitude: 74.0060))
_ = searchEngine!.search(textQuery: query, options: searchOptions) { (searchError, searchResultItems) in
guard searchResultItems != nil else {
return
}
for index in 0..<searchResultItems!.count {
let number = index + 1
print("Location \(number): \(searchResultItems![index])")
}
}
}
}
As explained here, you should instantiate the sdk manually since probably when your code is executed you don't have any map loaded yet (showing the map will automatically instantiate the sdk). So all you need is
// We must explicitly initialize the HERE SDK if no MapView is present.
do {
try SDKInitializer.initializeIfNecessary()
} catch {
fatalError("Failed to initialize HERE SDK")
}
before instantiating the SearchEngine

NSClassFromString from myClass [duplicate]

This question already has an answer here:
NSClassFromString returning nil for nested class
(1 answer)
Closed 3 years ago.
I have my custom class in extension UIImage like this
extension UIImage {
class AssetItem: NSObject {
}
}
when I try get class from NSClassFromString like this
NSClassFromString("UIImage.AssetItem")
I receive nil. How I can do it? I need get it class from String.
actually I try to do a tree with names, for can get exec like it NavigationBar.additionMenu and receive string "NavigationBar.additionMenu".
protocol EIAssetRoot {
}
protocol EIAssetFolder {
static func name(_ key: String) -> String
}
extension EIAssetFolder {
static func name(_ key: String = #function) -> String {
let full = "\(String(reflecting: self)).\(key)"
let lastSpace = full.components(separatedBy: ":").last ?? full
let components = lastSpace.components(separatedBy: ".")
var rootComponents = components
var rootFounding = false
repeat {
rootComponents = rootComponents.dropLast()
let name = rootComponents.joined(separator: ".")
if let anyClass = NSClassFromString(name) {
if anyClass is EIAssetRoot {
rootFounding = true
}
}
} while rootComponents.count > 0 && rootFounding == false
let keyComponents = components.dropFirst(rootComponents.count)
let name = keyComponents.joined(separator: ".")
return name
}
}
extension UIImage {
#objc class AssetItem: NSObject, EIAssetRoot {
class NavigationBar: EIAssetFolder {
static var additionMenu: String { get { return name() } }
static var save: String { get { return name() } }
static let toLeft: String { get { return name() } }
static func toRight: String { get { return name() } }
}
}
}
this I try build string from class name and trunc first part to class EIAssetRoot
I don't like doing in by enum because it looks like .NavigationBar(.Menu(.SecondMenu(.additionMenu))) too meny ()
You need to "unhide" AssetItem by moving it out of the UIImage extension and up to the top level. Objective-C can never "see" a nested type like UIImage.AssetItem — and NSClassFromString is Objective-C / Cocoa.
However, it would be even better to ask yourself why you need this. In Swift, an attempt to use NSClassFromString is first and foremost a Bad Smell. You are probably trying to do something here that can be done in a correct Swifty way, without involving Objective-C Cocoa at the back end. But you have not revealed what it is.
You will have to access the class by an explicitly defined name like this. These symbols are defined in the global scope in Objective-C (so no .'s are allowed in the name):
extension UIImage {
#objc(UIImageAssetItem)
class AssetItem: NSObject {
}
}
let cls = NSClassFromString("UIImageAssetItem")

Safely unwrapping optional with guard let in init()

I think I probably missed the point of how this works but I have a class that needs to use a global optional value in several of its methods and right now I unwrapped it inside every method but I thought I could just unwrap the value in init(). Am I doing it wrong or is this now how it's supposed to work? - Thank you.
let iCloudPath = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
class iCloudManager {
init() {
guard let iCloudPath = iCloudPath else { return }
}
function1(){
// uses iCloudPath but returns 'Value of optional type 'URL?' must be unwrapped to a value of type 'URL''
}
function2(){
// uses iCloudPath but returns 'Value of optional type 'URL?' must be unwrapped to a value of type 'URL''
}
}
Store the result as a property of your objects. Better yet, use a static property, not a global.
class iCloudManager {
static let defaultPath = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
let path: URL
init?() {
guard let path = iCloudManager.defaultPath else { return nil }
self.path = path
}
func function1() {
// uses self.path
}
func function2() {
// uses self.path
}
}

Can I check if an optional is nil by using it as an argument? [duplicate]

This question already has an answer here:
Propagate an optional through a function (or Init) in Swift
(1 answer)
Closed 5 years ago.
I have a class with an optional zoomURL property let zoomURL : String?
I've been playing around with optional chaining to try and shorten the amount of nil checks I make. I know for the below I could easily check if the let zoomURLString = meeting.zoomURL but is it possible to skip this step and use it immediately as an argument within a function and check if this function is nil?
For example: (This fails)
if let parsedZoomURL = URL(string: meeting.zoomURL?){
//do stuff
}
You can use the
public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
method of Optional:
if let parsedZoomURL = zoomURL.flatMap( { URL(string: $0) }) {
//do stuff
}
or shorter (as someone noticed in a now deleted comment):
if let parsedZoomURL = zoomURL.flatMap(URL.init) {
//do stuff
}
The optional binding succeeds only if zoomURL is not nil
and the closure (which is then called with the unwrapped value
of zoomURL) does not return nil.
Swift will not chain nils on method calls, but it will let you use the same chaining syntax with an extension property:
extension String {
var asURL : URL {
get {
return URL(string: self)!
}
}
}
Now you can use chaining as usual:
if let parsedZoomURL = meeting.zoomURL?.asURL {
//do stuff
}
If you really want to you can create an init extension for URL that supports nil values to be passed. Returns nil if the string is nil.
extension URL {
init?(string: String?) {
guard let url = string else { return nil }
self.init(string: url)
}
}
Usage:
if let url = URL(string: meeting.zoomUrl) {
// Do stuff
}

Set new value with computed properties

i have a model object and i want to set new value to the object.
bellow i have mentioned the object variable and initialization
private var _data: NSMutableDictionary
// MARK:- Init
init(data: [String: AnyObject])
{
_data = NSMutableDictionary(dictionary: data)
}
How can i set a new value with setter. bellow i have mentioned the computed variable
var name: String? {
get {
if let nameObject = _data.objectForKey("network")?.objectForKey("name") {
return (nameObject as! String)
} else {
return nil
}
}
set {
}
}
need to complete the setter
Edit
I could found the answer for this question.
I need to change the name of the _data object. So i have to update name without change other variables in side the _data. so i keep a mutable copy of the _data object and changed the new value there. then updated the _data object.
Something like
set {
_data.objectForKey("network")?.setObject(newValue, forKey: "name")
}
How about this:
var name: String? {
get {
return _data["network"]?["name"] as? String
}
set {
if let network = _data["network"] as? Dictionary {
network["name"] = newValue
} else {
let network: [String:AnyObject] = ["name": newValue]
data["network"] = network
}
}
}
The setter also takes care of the situation the network key doesn't exist. If also _data can be nil then an extra if-let can be added to address this situation too.
BTW, I also added a shorter version of the getter.
Not really sure what you are trying to do here but can't you just write this:
set {
_data.objectForKey("network")?.objectForKey("name") = newValue
}
Edit: Wrong function, should have been:
set {
_data.objectForKey("network")?.setObject(newValue, forKey: "name")
}