Where to implement CLLocationManager - core-location

I have an app with a tab bar and 3 tabs. The current location of the user is going to be needed to be known on any of the three tabs. Would the best place to implement CLLocationManager be in the app delegate in this case?
Is it ok (good practise?) to put the CLLocationManager delegate methods in the app delegate m file?
Where would you suggest i place the CLLocationManager as I'm going to be calling -startUpdatingLocation from any of the three tabs?
Thanks

The app delegate is a reasonable place to put it. Another option would be to create a custom singleton factory class that has a class method that returns your location manager delegate and implement the delegate methods there. That would keep your app delegate class cleaner.
Here's a skeleton singleton class implemention based off of Peter Hosey's "Singletons in Cocoa: Doing them wrong". This may be overkill, but it's a start. Add your delegate methods at the end.
static MyCLLocationManagerDelegate *sharedInstance = nil;
+ (void)initialize {
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
+ (id)sharedMyCLLocationManagerDelegate {
//Already set by +initialize.
return sharedInstance;
}
+ (id)allocWithZone:(NSZone*)zone {
//Usually already set by +initialize.
#synchronized(self) {
if (sharedInstance) {
//The caller expects to receive a new object, so implicitly retain it
//to balance out the eventual release message.
return [sharedInstance retain];
} else {
//When not already set, +initialize is our caller.
//It's creating the shared instance, let this go through.
return [super allocWithZone:zone];
}
}
}
- (id)init {
//If sharedInstance is nil, +initialize is our caller, so initialze the instance.
//If it is not nil, simply return the instance without re-initializing it.
if (sharedInstance == nil) {
if ((self = [super init])) {
//Initialize the instance here.
}
}
return self;
}
- (id)copyWithZone:(NSZone*)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
// do nothing
}
- (id)autorelease {
return self;
}
#pragma mark -
#pragma mark CLLLocationManagerDelegateMethods go here...

I simply included my LocationManager in my AppDelegate directly, since it added little code.
However if you are going to include your LocationManager in the AppDelegate, then you should consider using NSNotifications to alert your viewcontrollers of the location updates your AppDelegate receives.
See this link
Send and receive messages through NSNotificationCenter in Objective-C?

Related

save uiimageview to coredata as binary data swift (5)

I am trying to save a imageview as a image to binary data in core data. My code is not working. It has a compile error. In View controller it is not regisitering cdHandler. All i want to do is save the the imaveview as binary data in a core data model.I have 2 classes a app delegate and a view controller.
CLASS VIEW CONTROLLER
import UIKit
import CoreData
class ViewController: UIViewController {
var canVasView = UIImageView()
#objc func hhh() {
let photo = self.canVasView.image
let data = photo!.pngData()
if cdHandler.saveObject(pic: data!){
}
}
}
APP DELEGATE
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Model")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
class cdHandler: NSObject {
private class func getContext() -> NSManagedObjectContext {
let appdeleagetzz = UIApplication.shared.delegate as! AppDelegate
return appdeleagetzz.persistentContainer.viewContext
}
class func saveObject(pic: Data, userName: String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(pic, forKey:"pic")
managedObject.setValue(userName, forKey:"userName")
do {
try context.save()
return true
} catch {
return false
}
}
class func deletObject(user: User) -> Bool {
let context = getContext()
context.delete(user)
do {
try context.save()
return true
} catch {
return false
}
}
class func fetchObject() -> [User]? {
do {
let context = getContext()
return try context.fetch(User.fetchRequest())
} catch {
return [User]()
}
}
}
}
The error message, *Value of type 'AppDelegate' has no member named 'persistentContainer', explains the problem. Indeed, when I look at the code for your AppDelegate class, I can confirm that it has no member named 'persistentContainer'. (If I am reading it correctly, the last two lines in the file are closing curly brackets. The first one closes your cdHandler nested class, and the second one closes your AppDelegate class.)
Do the following exercise. In Xcode, click in the menu: File > New Project and select iOS, Application and Single View App. Name your new project Junk. Switch on the Core Data checkbox. Click button Create. After it is done, look at the AppDelegate.swift which Xcode created, and in the AppDelegate class, you see it contains 8 functions (func). The 7th one is lazy var persistentContainer. Aha! The compiler is telling you that you probably should not have deleted those 8 functions, persistentContainer in particular.
You should copy that persistentContainer func from that Junk project into your AppDelegate class in your real project. Or, to head off future trouble, consider copying most of the other 7 funcs also. As you can see, most of them don't do anything except provide comments with explanations that are useful for beginners. After you are done copying, close the Junk project. (I overwrite my Junk project with a new Junk project several times in a typical week, especially when answering StackOverflow questions.)
That should fix this particular error and answer this question. Onward to the next issue. :)
Response to comment that you still get the error with cdHandler
Having nothing else to go on, I presume that the error that you are referring to is the compiler error still in your screenshot. In other words, you are saying that adding the persistentContainer definition did not make it any better.
Well, it works for me. Please replace all of the code in your AppDelegate.swift class with the following, build and run it…
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
AppDelegate.cdHandler.testGetContext()
return true
}
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Junk")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
class cdHandler: NSObject {
private class func getContext() -> NSManagedObjectContext {
let appdeleagetzz = UIApplication.shared.delegate as! AppDelegate
return appdeleagetzz.persistentContainer.viewContext
}
class func testGetContext() {
let context = getContext()
print("getContext() succeeded, got \(context)")
}
class func saveObject(pic: Data, userName: String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(pic, forKey:"pic")
managedObject.setValue(userName, forKey:"userName")
do {
try context.save()
return true
} catch {
return false
}
}
class func deletObject(user: NSManagedObject) -> Bool {
let context = getContext()
context.delete(user)
do {
try context.save()
return true
} catch {
return false
}
}
}
}
You see that compiles with no errors. Also, it runs and the AppDelegate.cdhandler.getContext() method works. As you can see, in AppDelegate.application(application:didFinishLaunchingWithOptions:), I have added a call to a new method which I defined later,AppDelegate.cdHandler.testGetContext()`. It works perfectly.
Are you getting a different error now? If so, you need to specify whether it is a Build or Run error. In either case, copy and paste the text of the error into your question, and tell us where it occurs.

xsp.extlib.convstate returns null

I have an Xpage application that uses the extension library where the xsp.extlib.convstate is 'null' for one of three users until they manually refresh page. All three users access application via RDP using Citrix and internet options are the same for all three. Trying to figure out why this would be happening. The application is only on one 9.0.1 server.
From the looks of the source code, if there hasn't been a conversationState initialised yet, the conversationState would not be initialised until either:
after the Render Response phase (in the phase listener: com.ibm.xsp.extlib.component.layout.impl.ApplicationPhaseListener)
#SuppressWarnings("unchecked") // $NON-NLS-1$
public void afterPhase(PhaseEvent event) {
if(event.getPhaseId()==PhaseId.RENDER_RESPONSE) {
// After the render phase, we save the conversion state
ConversationState.saveInSession(event.getFacesContext());
}
}
in the setParent method of the UIApplicationLayout, and this seems to be guarded by a 'isRestoringState' condition, which means I don't think this would run on the first view of a page as there wouldn't be any state to restore.
#Override
public void setParent(UIComponent parent) {
super.setParent(parent);
if( null == parent ){ // removing parent
return;
}
// TODO should move this initialization to initBeforeContents instead
FacesContextEx context = (FacesContextEx) getFacesContext();
if(null != context && !context.isRestoringState()) {
ConversationState cs = ConversationState.get(context, FacesUtil.getViewRoot(this), true);
// Initialize the conversation state
// Set the current navigation path to the UserBean
ApplicationConfiguration conf = findConfiguration();
if(conf!=null) {
String navPath = conf.getNavigationPath();
if(StringUtil.isEmpty(navPath)) {
// If there isn't a navigation path that is defined, the use the default one
if(StringUtil.isEmpty(cs.getNavigationPath())) {
navPath = conf.getDefaultNavigationPath();
}
}
if(StringUtil.isNotEmpty(navPath)) {
cs.setNavigationPath(navPath);
}
}
}
}
So this might explain why it wouldn't be initialised until the 2nd page view.
You could try forcing an initialisation of the ConversationState before you try to use it, maybe in beforePageLoad, by calling one of the com.ibm.xsp.extlib.component.layout.ConversationState's get() methods.
Note the boolean parameter tells the method to create the ConversationState if it does not exist.
I don't do much ServerSide Javascript but I guess this works? The sentiment is correct.
#{javascript: com.ibm.xsp.extlib.component.layout.ConversationState.get(facesContext, true); }
If you are doing it in java then:
ConversationState.get(FacesContext.getInstance(), true);
Does this sound like an explanation of why you are seeing your behaviour?

Run loop on main thread in osx and ios

I can't find any reference on doing something that should be really basic: I'd like to have a method called "forever" on the main UI loop. I would be happy both with an way to call my method synced with the UI refresh rate, or by passing a custom time granularity, as I don't really need it to happen more often than every 50-100 ms. Both answers for C++ (Carbon) and Objective C are fine, even though I will eventually use it in a pure C++ application. If you could suggest also how to remove this timer, it would be great.
Please check the comments for a further explanation of the threading scenario where I want to use this.
something like
class MySyncedClass {
void start() {
// start calling "execute" member function on main loop every N ms
}
void stop() {
// stop calling "execute"
}
void execute() {
// do something
}
};
usually you do something like this in the application delegate in the method didFinishLaunchingWithOptions. When you use an ivar to save the current instance of NSTimer, you can stop it anytime.
#implementation AppDelegate {
NSTimer *_timer;
}
- (void) start {
_timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(execute) userInfo:nil repeats:YES];
}
- (void) stop {
//reset timer
if (_timer != nil) {
[_timer invalidate];
_timer = nil;
}
}
- (void) execute {
//do something
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self start];
}
but you should use a callback via block if you only want to check another threads status.
if you want to execute something on the main thread from another thread you can use dispatch_get_main_queue:
dispatch_async(dispatch_get_main_queue(), ^{
//do something
});
Swift 3.0
DispatchQueue.main.async(execute: {
self._eventListTableView.reloadData()
})

MonoTouch Objective C Binding, Right Track?

I am trying to do this with the kiip library:
http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types
I am getting an error saying my binding project cannot be found, however, I did add a reference to it in the project.
Do I use the code like this:
public override void ViewDidLoad ()
{
var kp = new KiipMonoTouchBinding.IKPManager();
kp.InitWithKey("abc", "123");
}
Am I doing this correctly?
namespace KiipMonoTouchBinding
{
interface IKPManager
{
//kiip code
//KPManager* manager = [[KPManager alloc] initWithKey:#"0b56b49f621ad7f42fd85de7e461f9dd" secret:#"ac3abfdf5cb86ce0febba0c8afd2744e" testFrequency:100];
[Export("initWithKey:")]
void InitWithKey(string key, string secret);
//[[KPManager sharedManager] unlockAchievement:#"_achievement_id_"];
[Export ("unlockAchievement:")]
void UnlockAchievement(string achivementId);
//
//- (IBAction)saveLeaderboard {
// NSLog(#"save leaderboard");
// [[KPManager sharedManager] updateScore:100 onLeaderboard:leaderboard_id.text];
//}
//[[KPManager sharedManager] updateScore:_score_ onLeaderboard:#"_leaderboard_id_"];
[Export("updateScore:")]
void UpdateScore(int score, string leaderboardId);
//- manager:(KPManager*)manager didStartSession:(NSDictionary*)response {
[Export("didStartSession:response")]
void DidStartSession(NSDictionary response);
//updateLatitude:(double)37.7753 longitude:(double)-122.4189];
[Export("updateLatitude:_latitude, longitude")]
void UpdateLatitude(double latitude, double longitude);
[Export("updateUserInfo:info")]
void UpdateUserInfo(NSDictionary info);
// [[KPManager sharedManager] getActivePromos];
[Export("getActivePromos")]
void GetActivePromos();
// Update the user's location
// [manager updateLatitude:_latitude_ longitude:_longitude_];
// Update the User's information
// NSDictionary* info = [[[NSDictionary alloc] initWithObjectsAndKeys:
// _email_, #"email",
// _alias_, #"alias",
// nil]
// autorelease];
// [manager updateUserInfo:info];
}
Your binding has several problems.
Constructors must be declared as "IntPtr Constructor", so change the "void InitWithKey" to be:
[Export ("initWithKey:")]
IntPtr Constructor (string key);
The second problem is that the export you are using "initWithKey:" takes a single parameter (we know this because there is a single instance of the colon), so you might need to find out what the actual name of the constructor is, or use a single parameter (key), like I did in the sample.
Your binding for "DidStartSession" is wrong. Look at the signature which is "manager:didStartSession:" so it should be:
[Export ("manager:didStartSession:")]
void DidStartSession (KPManager manager, NSDictionary sessionREsponse);
Your UpdateLatitude is also wrong, again, the selector you added is incorrect, I can not guess what it is without looking at the code, but if this really gets two parameters (longitude and latitude), it would look like this (I am making the selector name up):
[Export ("updateLatitude:andLongitude:")]
void UpdateLocation (double latitude, double longitude)
UpdateUserInfo is also wrong, most likely it takes a single parameter (guessing again):
[Export ("updateUserInfo:")]
void UpdateUserInfo (NSDictionary info)
Notice that the "info" word, the name of the parameter is never part of the selector name.
The binding for getActivePromos also looks wrong, I suspect it should return a value, but you declared it as returning void.
There might be other problems as well.

MKAnnotationView RightCallOut button crashes my app when I click on it

I'm calling a service and returning a bunch of latitudes and longitudes which I'm then placing on a map using MapKit.
using MKAnnotationView I'm adding a RightCallOutButton to each annotation.
So I had to create a new MapDelegate. Code below.
If I click on the button I create the app crashes and I get an error from MonoTouch saying the selector is accings omething that has already been GC'd (garbage collected).
So my question would be, where should I set the RightCalloutAccessoryView and where should I create the button, if not in this code below?
public class MapDelegage : MKMapViewDelegate {
protected string _annotationIdentifier = "BasicAnnotation";
public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation) {
MKAnnotationView annotationView = mapView.DequeueReusableAnnotation(this._annotationIdentifier);
if(annotationView == null) {
annotationView = new MKPinAnnotationView(annotation, this._annotationIdentifier);
} else {
annotationView.Annotation = annotation;
}
annotationView.CanShowCallout = true;
(annotationView as MKPinAnnotationView).AnimatesDrop = true;
(annotationView as MKPinAnnotationView).PinColor = MKPinAnnotationColor.Green;
annotationView.Selected = true;
var button = UIButton.FromType(UIButtonType.DetailDisclosure);
button.TouchUpInside += (sender, e) => {
new UIAlertView("Testing", "Testing Message", null, "Close", null).Show ();
} ;
annotationView.RightCalloutAccessoryView = button;
return annotationView;
}
}
annotationView = new MKPinAnnotationView(annotation, this._annotationIdentifier);
...
var button = UIButton.FromType(UIButtonType.DetailDisclosure);
You should avoid declaring local variables to hold references you expect to outlive the method itself. Once there's no reference to annotationView or button the Garbage Collector (GC) is free to collect them (the managed part) even if it's native counterparts still exists. However when a callback to them is called you'll get a crash.
The easiest solution is to keep a list of them and (at the class level, i.e. a List<MKPinAnnotationView> field) clear the list when you destroy the view. The UIButton should not be necessary since there's a reference between the view and it.
NOTE: work is being done to hide this complexity from developers in future versions of MonoTouch. Sadly you cannot ignore such issues at the moment.

Resources