How do I find the coordinates of a address? - swift

I am making a app that places a point on the coordinates of an address using MapKit.
I have my class made and all my functions set up within the class.
I need to be able to return "getLocation()" which will be the string of an address and use that string with the CLGeoCoder().geocodeAdressString and get the coordinates.
Here are my classes
import UIKit
class Vendor {
private var name = String()
private var type = String()
private var location = String()
private var logo = UIImage()
required init(name: String, type: String) {
self.name = name
self.type = type
self.location = ""
self.logo = UIImage()
}
func getName() -> String {
return self.name
}
func setName(name: String) {
self.name = name
}
func getType() -> String {
return self.type
}
func setType(type: String) {
self.type = type
}
func getLocation() -> String {
return self.location
}
func setLocation(address: String) {
self.location = address
}
func getLogo() -> UIImage {
return self.logo
}
func setLogo(image: UIImage) {
self.logo = image
}
}

Assuming that the location in your vendor class are the street, city and country of the vendor your code might look something like this:
func geoCodeVendor() {
let vendorLocation = myVendor.getLocation
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(vendorLocation) { (placemarks, error) in
self.centerCoordinate = (placemarks?.first?.location?.coordinate)!
//Whather more you want to do in this completion handler.
}
}
Here you have created an instance of Vendor, myVendor in the class where you are geocoding your vendor. In that class you have created a property centerCoordinate = CLLocationCoordinate2D().
Usually, you have a vendor class with the name, address and city in separate properties. For instance:
class Vendor {
private var name = String()
private var type = String()
private var address = String()
private var city = String()
private var logo = UIImage()
}
Then your append the address and city in your getLocation function. Please, remind that geocoding works more accurate when the address is as complete as possible, That is, address (with number, city, country.
Hope this helps.

Related

Best Swift way to write Dictionary of String to Country

I want my Swift class FinderForCountry to find the Country with the specified name.
The code should also remember any countries (by name) that have already been found.
My existing Swift class has a [String: Country] variable, and a method findCountry() that takes both a String and a function that takes a Country.
public
class FinderForCountry {
private
var mapOfStringToCountry = [String: Country]()
public
func findCountry(from string: String, _ functionThatTakesCountry: #escaping (Country) -> Void) {
if let country = mapOfStringToCountry[string] {
functionThatTakesCountry(country)
} else {
DispatchQueue.main.async {
let country = Country(string)
self.mapOfStringToCountry[string] = country
functionThatTakesCountry(country)
}
}
}
}
Is this the best way to write the code, or is there a better way? For example:
public
class FinderForCountry {
private
var mapOfStringToCountry = [String: Country]()
public
func findCountry(from string: String, _ functionThatTakesCountry: #escaping (Country) -> Void) {
DispatchQueue.main.async {
if let country = self.mapOfStringToCountry[string] {
functionThatTakesCountry(country)
} else {
let country = Country(string)
self.mapOfStringToCountry[string] = country
functionThatTakesCountry(country)
}
}
}
}
Many thanks.
Yes, there is indeed a better way.
The escaping completion handler and dispatching the code to the main thread make no sense as there is nothing which is executed asynchronously.
Just return the country.
public class FinderForCountry {
private var mapOfStringToCountry = [String: Country]()
public func findCountry(from string: String) -> Country
{
if let country = self.mapOfStringToCountry[string] {
return country
} else {
let country = Country(string)
self.mapOfStringToCountry[string] = country
return country
}
}
}

Instance Member Cannot Be Used On Type - Firebase

I am new to Swift and I am following a tutorial on how to create a social media app with Xcode and Firebase. However, I got this error:
Instance member 'database' cannot be used on type 'DatabaseReference'
Here is my code:
import Foundation
import Firebase
class Post {
private var _username: String!
private var _userImg: String!
private var _postImg: String!
private var _likes: Int!
private var _postKey: String!
private var _postRef: DatabaseReference
var username: String {
return _userImg
}
var postImg: String {
get {
return _postImg
}set {
_postImg = newValue
}
}
var likes: Int {
return _likes
}
var postKey: String {
return _postKey
}
init(imgUrl: String, likes: Int, username: String, userImg: String) {
_likes = likes
_postImg = postImg
_username = username
_userImg = userImg
}
init(postKey: String, postData: Dictionary<String, AnyObject>) {
_postKey = postKey
if let username = postData["username"] as? String {
_username = username
}
if let userImg = postData["userImg"] as? String{
_userImg = userImg
}
if let postImage = postData["imageUrl"] as? String {
_postImg = postImage
}
if let likes = postData["likes"] as? Int {
_likes = likes
}
_postRef = DatabaseReference.database().reference().child("posts")
}
}
I get my error on the third to last line that says:
_postRef = DatabaseReference.database().reference().child("posts")
The database property is an instance type, meaning it must be referenced by an instance of DatabaseReference. Your call to DatabaseReference.database is accessing for a class, or static, type. You need to change your call to an instance of DatabaseReference.
Presumably, you need to initialize an instance of DatabaseReference. I don't know Firebase to know what is required for that, but that will take care of your issue.
Essentially:
let databaseReference = DatabaseReference() // Likely won't work, but some init method here will
_postRef = databaseReference.database()... // Whatever you need here
It sounds like you're looking for either:
_postRef = Database.database().reference("posts")
Or
_postRef = DatabaseReference.root.child("posts")

Swift optional chaining with non-nil value

I have the following program which works fine -
class Person {
var pet: Pet?
}
class Pet {
var name: String
var favoriteToy: Toy?
init(name: String) {
self.name = name
}
}
class Toy {
var name: String
init(name: String) {
self.name = name
}
}
let q = Person()
// Pet(name:"goofy")
// Toy(name:"teddy")
if let someToy = q.pet?.favoriteToy?.name {
print("This person's pet likes \(someToy).")
} else {
print("This person's pet does not have a favorite toy")
}
Prints:
This person's pet does not have a favorite toy
How to use the above code modified to print "This person's pet likes teddy."?
I know I will have not be able to use if let as there will be nothing to unwrap. So I have to write something like this instead of if let:
let someToy = q.pet.favoriteToy.name
print("This person's pet likes \(someToy).")
Should print "This person's pet likes the teddy."
I also know I have to put non-nil value something like this:
class Person {
var pet = Pet ()
}
Still I am having initialization problems. How to go about it?
This should solve your immediate needs...
let man = Person()
let goofy = Pet(name: "goofy")
let squeaky = Toy(name: "squeaky toy")
goofy.favoriteToy = squeaky
man.pet = goofy
But if a person is usually going to be initialized with a pet and a toy, and both of those classes are initialized with a string, then you might want to define a convenience initializer:
class Pet {
var name: String
var favoriteToy: Toy?
init(name: String) {
self.name = name
}
}
class Toy {
var name: String
init(name: String) {
self.name = name
}
}
class Person {
var pet: Pet?
convenience init(petName: String, toyName: String) {
self.init()
let toy = Toy(name: toyName)
let pet = Pet(name: petName)
pet.favoriteToy = toy
self.pet = pet
}
}
func test() {
let bill = Person(petName: "goofy", toyName: "squeaky ball")
guard let toyName = bill.pet?.favoriteToy?.name else { return }
print(toyName)
}
test()
One more thing: optional chaining can be combined with a guard statement to great effect in Swift.
Use ? = nil in your initializer to pass in some optional parameters.
class Person {
var pet: Pet?
init(pet: Pet? = nil) {
self.pet = pet
}
}
class Pet {
var name: String
var favoriteToy: Toy?
init(name: String, toy: Toy? = nil) {
self.name = name
self.favoriteToy = toy
}
}
class Toy {
var name: String
init(name: String) {
self.name = name
}
}
let q = Person(pet: Pet(name: "goofy", toy: Toy(name: "teddy")))
// Pet(name:"goofy")
// Toy(name:"teddy")
if let someToy = q.pet?.favoriteToy?.name {
print("This person's pet likes \(someToy).")
} else {
print("This person's pet does not have a favorite toy")
}

Swift 2.2 singleton

I am new in Swift. I am trying to parse some JSON data from web service and want a singleton class of user.But I got stuck to create the singleton. Here is my code:
import Foundation
class User {
private var success: String
private var userId: String
private var name: String
private var gender: String
private var email: String
private var userObject = [User]()
class var sharedInstane:User {
struct Singleton {
static var onceToken: dispatch_once_t = 0
static var instance:User? = nil
}
dispatch_once(&Singleton.onceToken){
Singleton.instance = User()
}
return Singleton.instance!
}
private init(success: String, userId: String, name: String, gender: String, email: String)
{
self.success = success
self.userId = userId
self.name = name
self.gender = gender
self.email = email
}
convenience init(dictionary: [String:AnyObject]) {
let success = dictionary["success"] as? String
let userId = dictionary["userId"] as? String
let name = dictionary["name"] as? String
let gender = dictionary["gender"] as? String
let email = dictionary["email"] as? String
self.init(success: success!, userId: userId!, name: name!, gender: gender!, email: email!, )
}
func callWebserviceToLoadUserInfo (url:String, param:[String:AnyObject],completeHandler:(Bool?,String) -> ())
{
let connection = ServerConnection()
connection.getJSONDataForWebService(url, params: param) { (response, error) in
// code goes here
var responseDict = response as! [String : AnyObject]
responseDict = responseDict["responseDict"] as! [String : AnyObject]
if responseDict["success"] as! String == "1" {
for dict in responseDict {
let user = User(dictionary: (dict as! [String:AnyObject]))
self.userObject.append(user)
}
print("user : \(self.userObject[0].name)")
}else{
// error goes here
}
}
}
}
Can any one please help me how should I do this code?
The singleton in the single line sample code.
class TheOneAndOnlyKraken {
static let sharedInstance = TheOneAndOnlyKraken()
private init() {} //This prevents others from using the default '()' initializer for this class.
}
For more details.
Using Krakendev's single-line singleton code, cited by Maheshwar, and turning your convenience init into an instance function to be called with User.sharedInstance.initialize(dictionary):
import Foundation
class User {
// Here you declare all your properties
// "private var" and all that jazz
static let sharedInstance = User()
private init() {
// If you have something to do at the initialization stage
// you can add it here, as long as it does not involve
// arbitrary values that you would pass as parameters.
}
func initialize(dictionary: [String:AnyObject]) {
// Transfer the values of the dictionary to each `self.property`.
// Be careful while using `as?` as you may have to deal with
// optionals. No need to call `self.init` at the end, because
// this is now a regular `func`.
}
// Add the rest of your stuff here
}
One note about how you were working inside of that convenience initializer: if you do property = SomeClass.someMethod().someProperty as? SomeType, then property will be of type SomeType?, or Optional(SomeType). According to The Swift Programming Language,
The conditional form, as?, returns an optional value of the type you are trying to downcast to.
While User was not instantiated at least one time sharedInstance will return nil. After the first successful instantiation of the User, sharedInstance starts return it and that's became impossible to instantiate another one User as singleton pattern requires it. Consider this:
class User {
private static var sharedUser: User?
class var sharedInstance: User? {
return sharedUser
}
private init(success: String, userId: String, name: String, gender: String, email: String)
{
//User initialization code here
User.sharedUser = self
}
convenience init?(dictionary: [String:AnyObject]) {
guard User.sharedUser == nil else {
return nil
}
//dictionary parsing code is here
self.init(success: success!, userId: userId!, name: name!, gender: gender!, email: email!)
}
}
Client's code:
User.sharedUser
//return nil
let dict: [String:AnyObject] = ["success": "success", "userId":"userId", "name":"name", "gender":"gender","email":"email"]
User(dictionary: dict)
//creates User
User.sharedUser
//returns just created user
User(dictionary: dict)
//return nil
You should think about making this two classes, so that User is your model class and then create a manager to handle all the users (which seems to be your goal).
So in User remove the sharedInstane part and create a second singleton class, e.g. called UserManager, with the standard way to create a singleton in Swift. Then you can keep the way you're creating your user and in the end just assign it to the singleton:
class UserManager {
static let sharedInstance = UserManager()
var users = [User]()
}
// in your code:
...
for dict in responseDict {
let user = User(dictionary: (dict as! [String:AnyObject]))
UserManager.sharedInstance.users.append(user)
}
...

Cannot assign to the result of this expression with generics

I have the following generic class where I want to manage a string hash:
class NamedProfile<T> {
private var set = [String:T]()
private var profiles = [String]()
private let userDefaults = NSUserDefaults.standardUserDefaults()
private let profileName:String
var currentSet = ""
init(name:String, set:[String:T]) {
profileName = name
self.set = set
if let existingProfiles = userDefaults.objectForKey(name) as? [String] {
profiles = existingProfiles
}
for key in profiles {
if let existingProfile = userDefaults.objectForKey(profileNamed(name)) as? T {
set[key] = existingProfile // <-- error
}
}
}
private func profileNamed(name:String) -> String { return "\(profileName) \(name)" }
}
Why does the compiler croak in the above assignment?
In
init(name:String, set:[String:T]) {
// ...
set[key] = existingProfile // <-- error
// ...
}
set refers to the (immutable) method parameter.
Use self.set instead to refer to the property.