iOS Cllocationmanager in a Separate Class

iOS CLLocationManager in a separate class

Create a singleton class which has a latitude and longitude properties, startLocating and endLocating. In the class, create a CLLocationManager instance, and set its delegate to be the singleton. In startLocating and endLocating, call the appropriate methods of the CLLocationManager instance. Make the delegate methods update the latitude and longitude properties. In other ViewControllers, read this singleton's latitude and longitude properties.

To know when to read those properties from another ViewController, set an observer on these properties (see the NSKeyValueObserving Protocol Reference

Before doing this, look up the Internets for existing code.

After doing this, upload it to GitHub with a permissive license.

Add CLLocationManagerDelegate to a separate class

As written, you have to ensure that the LocationHandler instance is a property of the view controller, not a local variable. You want to make sure it doesn’t fall out of scope and is deallocated before the delegate method has a chance to be called.

Location Manager in seperate class in Swift

First of all please name custom structs and classes with starting uppercase letter.

The error occurs because there is no strong reference to the locationRequest class.

Either design the class as singleton

class LocationRequest: NSObject, CLLocationManagerDelegate {

static let shared = LocationRequest()

...

}

...

class TodayViewController: UIViewController {

var locationRequest = LocationRequest.shared

override func viewDidLoad() {
super.viewDidLoad()
}

or create a lazy instantiated property

class LocationRequest: NSObject, CLLocationManagerDelegate { ... }

...

class TodayViewController: UIViewController {

lazy var locationRequest = LocationRequest()

override func viewDidLoad() {
super.viewDidLoad()
}
}

Handling CLLocationManager delegate from another class

You have several options, really. One could be making your second class a property of your first class (singleton pattern would fit nice here, I guess). Then you can either declare a protocol in your second class and notify your first class via delegate methods (non-singleton implementation) or use NSNotificationCenter to post a notification (singleton implementation).

The second option would be to pass a block with completion handler to the second class. You could declare your method in the second class like this, for example (adjust return type and arguments of the block, if needed):

- (void)updateLocationWithCompletionHandler:(void (^)(void))completion;

Implement it so that you call the completion block after you get the geolocation update results.

And call it from the first class like:

[self.secondClass updateLocationWithCompletionHandler:^
{
// Your completion code here.
}];

Hope this helps (sorry, didn't check the code in Xcode, get rid of typos, if any).

Location class using CLLocationManager in swift

The problem is that locUtil, to which you have assigned your LocationUtil instance, is an automatic variable — that is, it is local to the viewDidLoad function. Thus, when viewDidLoad runs, locUtil (and your LocationUtil instance) comes into existence, exists for one more line, and vanishes in a puff of smoke. Your LocationUtil instance is thus destroyed once more — taking its instance variables, such as the location manager, with it.

Thus there is no time for anything to happen. The location manager and its delegate exist for about a millionth of a second. That is not long enough to work out your location!

How to use locationManager() in multiple ViewControllers

I tried to implement a singleton CLLocationManager class, I think you can modify the following class to implement some additional methods.

import Foundation

class LocationSingleton: NSObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private var latitude = 0.0
private var longitude = 0.0

static let shared = LocationSingleton()

private override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
locationManager.requestAlwaysAuthorization() // you might replace this with whenInuse
locationManager.startUpdatingLocation()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
}
}

private func getLatitude() -> CLLocationDegrees {
return latitude
}

private func getLongitude() -> CLLocationDegrees {
return longitude
}

private func zipCode() {
// I think you can figure way out to implemet this method
}

private func city() {
// I think you can figure way out to implemet this method
}
}

iOS 10: CLManager as a separate class - receiving call backs

In LocClass.h file add the protocol method

@protocol LocationUpdateProtocol <NSObject>
@optional
// Override this method in UIViewController derived class to get back the location details.
-(void)locationUpdatedWithManager:(CLLocationManager *)manager newLocations:(NSArray *)locations;
@end

@interface LocClass : NSObject
@property (nonatomic, weak) NSObject<LocationUpdateProtocol> *delegate;
@end

Then in your .m file

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
//the usual stuff here...

if([self.delegate conformsToProtocol:@protocol(LocationUpdateProtocol)] && [self.delegate respondsToSelector:@selector(locationUpdatedWithManager:newLocations:)]) {
[self.delegate locationUpdatedWithManager:manager newLocations:locations];
}
}

Now the mainViewcontroller class should implement this Protocol

@interface ViewController () <LocationUpdateProtocol>

And the place where you initilaze location manager class, set the delegate

- (void)viewDidLoad {

locMan = [[LocClass alloc] init];
[locMan startLocationManager];
locMan.delegate = self;
...
}

//Will get the delegate callback here.
- (void)locationUpdatedWithManager:(CLLocationManager *)manager newLocations:(NSArray *)locations{
}

Get location results from another class in swift

You can define a closure to run after getting location in your GPSLocation class. You can achieve it in two way:

You can have a variable of a block code in your GPSLocation class like below :

typealias completionHanlder = (_ lat: String, _ lng: String) -> Void
var completion: completionHanlder?

then in your Post class after instantiating GPSLocation you can pass a block of codes like :

getUserLocation.completion = {
// do any stuff here
}

OR you can pass a block of code to your getGPSLocation function. here is how to redefine your function :

func getGPSLocation(completion: (_ lat: String, _ lng: String) -> Void) {        
let locManager = CLLocationManager()
var currentLocation: CLLocation!
locManager.desiredAccuracy = kCLLocationAccuracyBest

if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse || CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {

currentLocation = locManager.location

let latitude = String(format: "%.7f", currentLocation.coordinate.latitude)
let longitude = String(format: "%.7f", currentLocation.coordinate.longitude)
let location = CLLocation(latitude: currentLocation.coordinate.latitude, longitude: currentLocation.coordinate.longitude)

fetchCountryAndCity(location: location, completion: { countryCode, city in
delegate?.fetchedLocationDetails(location: location, countryCode: countryCode, city: city)
}) { delegate?.failedFetchingLocationDetails(error: $0) }

debugPrint("Latitude:", latitude)
debugPrint("Longitude:", longitude)

completion(latitude, longitude) // your block of code you passed to this function will run in this way

}

}

and this would be your Post class :

class Post {

func getLocation() {
// Get user GPS location (longitude, latitude, Country Code, City)
let getUserLocation = GPSLocation()
getUserLocation.getGPSLocation { (lat, lng) in

debugPrint("Latitude:", lat)
debugPrint("Longitude:", lng)
// HERE I NEED to PRINT longitude, latitude, Country Code, City
}

}
}

This closure you put here would run whenever completion block called in getGPSLocation function as I rewrite your function above.

How do I get Location coordinates to update in another class?

If you keep the location manager as an instance variable, you can access them from anywhere by accessing the current application's delegate property like this.

if let delegate = UIApplication.sharedApplication().delegate as? AppDelegate {
let manager = delegate.locationManager
}

The reality though is that if you are trying to improve your app architecture, I would not personally put the location logic in your app delegate. That feels like the wrong decision to me. If I were you, I would make a LocationManager singleton class to address both issues.

If you need dependent classes to update in real-time, I would post an NSNotification and listen for it on the classes that need to update.



Related Topics



Leave a reply



Submit