2013-02-26 79 views
0

所以我对此是完全陌生的。 我下面一个当地的天气教程如何将本地变量更改为实例变量?

http://www.icodeblog.com/2010/09/03/adding-local-weather-conditions-to-your-app-part-12-implementing-corelocation/

它不工作,因为它应该。当我点击RUN时,会弹出一个窗口,提示您是否允许此应用访问位置管理器。但是在我有机会击中它之前消息就消失了,那么应用程序什么都不做。

下面是我的代码...在研究,我发现这个信息

虽然难以追查,这个解决方案是非常简单的。

通过大量的试验和错误,我发现当你第一次尝试访问应用程序中的任何位置服务时,弹出位置访问对话框,对话框自己消失(没有任何用户交互) CLLocationManager对象在用户响应对话之前被释放。

我在我的viewDidLoad方法中创建了CLLocationManager实例。由于这是该方法的本地实例,因此该方法完成执行后,该实例将由ARC发布。实例一发布,对话消失。解决方案相当简单。从一个方法级变量是一个类级实例变量改变CLLocationManager实例。现在CLLocationManager实例只有在类被卸载后才被释放。

这可能是答案,但我不知道如何从方法级别更改为类级可变。

有人可以协助改变这个级别的变量吗?

这里是我的代码

#import <Foundation/Foundation.h> 
#import <CoreLocation/CoreLocation.h> 

@protocol LocationGetterDelegate <NSObject> 
@required 
- (void) newPhysicalLocation:(CLLocation *)location; 
@end 

@interface LocationGetter : NSObject 
<CLLocationManagerDelegate>{ 
    CLLocationManager *locationManager; 
    id delegate; 
} 

-(void)startUpdates; 

@property (nonatomic, retain) CLLocationManager *locationManager; 
@property (nonatomic, retain) id delegate; 

@end 


    #import "LocationGetter.h" 
    #import <CoreLocation/CoreLocation.h> 

@implementation LocationGetter 

@synthesize locationManager,delegate; 
BOOL didUpdate = NO; 

- (void) startUpdates{ 
    NSLog(@"Starting Location Updates"); 

    if (locationManager == nil) 
     locationManager = [[CLLocationManager alloc]init]; 
    locationManager.delegate = self; 

    locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; 
    [locationManager startUpdatingLocation]; 
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 
{ 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your location could not be determined." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 
    [alert show]; 
} 

// Delegate method from the CLLocationManagerDelegate protocol. 
- (void)locationManager:(CLLocationManager *)manage didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{ 
    if (didUpdate) 
     return; 

    didUpdate = YES; 
    // Disable future updates to save power. 
    [locationManager stopUpdatingLocation]; 

    // let our delegate know we're done 
    [delegate newPhysicalLocation:newLocation]; 
} 

@end 



    #import <UIKit/UIKit.h> 
    #import "LocationGetter.h" 

@class ViewController; 

@interface AppDelegate : UIResponder 
    <UIApplicationDelegate, LocationGetterDelegate> 
{ 
    UIWindow *window; 
    ViewController *viewController; 
    CLLocation *lastKnownLocation; 

} 

@property (retain, nonatomic) UIWindow *window; 

@property (retain, nonatomic) ViewController *viewController; 

@property (nonatomic, retain) CLLocation *lastKnownLocation; 

@end 




    #import "AppDelegate.h" 
    #import "ViewController.h" 
    #import "LocationGetter.h" 

@implementation AppDelegate 

@synthesize lastKnownLocation; 
@synthesize viewController; 
@synthesize window; 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
// self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
// // Override point for customization after application launch. 
// self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 
// self.window.rootViewController = self.viewController; 
// [self.window makeKeyAndVisible]; 

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 
    spinner.center = CGPointMake(self.viewController.view.frame.size.width/2, self.viewController.view.frame.size.height/2); 
    [spinner startAnimating]; 

    [viewController.view addSubview:spinner]; 

    // get our physical location 
    LocationGetter *locationGetter = [[LocationGetter alloc] init]; 
    locationGetter.delegate = self; 
    [locationGetter startUpdates]; 

    // Add the view controller's view to the window and display. 
    [window addSubview:viewController.view]; 
    [window makeKeyAndVisible]; 



    return YES; 
} 

- (void)applicationWillResignActive:(UIApplication *)application 
{ 
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 
} 

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 
} 

- (void)applicationWillEnterForeground:(UIApplication *)application 
{ 
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 
} 

- (void)applicationDidBecomeActive:(UIApplication *)application 
{ 
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 
} 

- (void)applicationWillTerminate:(UIApplication *)application 
{ 
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 
} 

- (void)newPhysicalLocation:(CLLocation *)location { 

    // Store for later use 
    self.lastKnownLocation = location; 

    // Remove spinner from view 
    for (UIView *v in [self.viewController.view subviews]) 
    { 
     if ([v class] == [UIActivityIndicatorView class]) 
     { 
      [v removeFromSuperview]; 
      break; 
     } 
    } 

    // Alert user 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Location Found" message:[NSString stringWithFormat:@"Found physical location. %f %f", self.lastKnownLocation.coordinate.latitude, self.lastKnownLocation.coordinate.longitude] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 
    [alert show]; 
} 


@end 

回答

2

有几件事情需要修复。首先,你的locationManager已经是一个实例变量。那里没有什么可以改变的。但是你声明locationManager属性,但从不使用它。摆脱财产或实际使用它。如果你保留这个财产,它不需要公开,因为没有外部的阶级正在使用它。

此外,您delegate属性定义不正确。

您所遇到的真正问题是由于应用程序委托实现。您创建的LocationGetter本地实例,然后让它走出去的范围在方法的结束。您需要将一个LocationGetter实例变量添加到您的应用程序委托。这将允许实例留不仅仅是didFinishLaunchingWithOptions:方法活得更长。

这是我怎么会更新代码(假设ARC启用):

LocationGetter.h:

#import <Foundation/Foundation.h> 
#import <CoreLocation/CoreLocation.h> 

@protocol LocationGetterDelegate <NSObject> 
@required 
- (void) newPhysicalLocation:(CLLocation *)location; 
@end 

@interface LocationGetter : NSObject 

-(void)startUpdates; 

@property (nonatomic, weak) id<LocationGetterDelegate> delegate; 

@end 

LocationGetter.m:

#import "LocationGetter.h" 
#import <CoreLocation/CoreLocation.h> 

@interface LocationGetter() <CLLocationManagerDelegate> 

@property (nonatomic, strong) CLLocationManager *locationManager; 

@end 

@implementation LocationGetter { 
    BOOL didUpdate = NO; 
} 

- (void) startUpdates{ 
    NSLog(@"Starting Location Updates"); 

    if (self.locationManager == nil) 
     self.locationManager = [[CLLocationManager alloc]init]; 
    self.locationManager.delegate = self; 

    self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; 
    [self.locationManager startUpdatingLocation]; 
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 
{ 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your location could not be determined." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 
    [alert show]; 
} 

// Delegate method from the CLLocationManagerDelegate protocol. 
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{ 
    if (didUpdate) 
     return; 

    didUpdate = YES; 
    // Disable future updates to save power. 
    [manager stopUpdatingLocation]; 

    // let our delegate know we're done 
    [self.delegate newPhysicalLocation:newLocation]; 
} 

@end 

AppDelegate.h:

#import <UIKit/UIKit.h> 

@class ViewController; 

@interface AppDelegate : UIResponder <UIApplicationDelegate> 

@property (strong, nonatomic) UIWindow *window; 
@property (strong, nonatomic) ViewController *viewController; 
@property (nonatomic, strong) CLLocation *lastKnownLocation; 

@end 

应用程序Delegate.m:

#import "AppDelegate.h" 
#import "ViewController.h" 
#import "LocationGetter.h" 

@interface AppDelegate() <LocationGetterDelegate> 
@property (nonatomic, strong) LocationGetter *locationGetter; 
@end 

@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
// self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
// // Override point for customization after application launch. 
// self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 
// self.window.rootViewController = self.viewController; 
// [self.window makeKeyAndVisible]; 

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 
    spinner.center = CGPointMake(self.viewController.view.frame.size.width/2, self.viewController.view.frame.size.height/2); 
    [spinner startAnimating]; 

    [viewController.view addSubview:spinner]; 

    // get our physical location 
    self.locationGetter = [[LocationGetter alloc] init]; 
    self.locationGetter.delegate = self; 
    [self.locationGetter startUpdates]; 

    // Add the view controller's view to the window and display. 
    [window addSubview:viewController.view]; 
    [window makeKeyAndVisible]; 

    return YES; 
} 
+0

好点,我没有看那里! +1 – borrrden 2013-02-26 01:42:18

+0

顺序... locationManager已经是一个实例变量。由于我不使用它,我将它从哪个区域删除?然后如何将一个LocationGetter的实例添加到appdelegate? – solarissf 2013-02-26 01:46:31

+0

查看我更新的答案和代码。我很快输入了这个,可能会有错误。 – rmaddy 2013-02-26 01:53:03

1

我想你的意思改变它是一个实例变量不是类变量(Objective-C中没有这样的概念)。那么,你已经做到了。凡是住在这里:

@interface Foo : SuperFoo 
{ 
    //... 
} 

或者在这里:

@implementation Foo 
{ 
    //... 
} 

是一个实例变量。

+0

在帖子中我发现..它说ARC发布了位置管理器的实例变量,你认为这是真的吗? – solarissf 2013-02-26 01:30:24

+0

是的,这是真的,但它不是“早”。 ARC在正确的地方发布了它。当一个强变量超出范围并且没有更强的引用时,它将被释放。 – borrrden 2013-02-26 01:35:54

+0

所以我想我试图找出为什么说,允许...的弹出窗口正在消失在我身上。任何想法?你认为它是因为我有位置经理在一个实例,它不应该? – solarissf 2013-02-26 01:38:11