2013-02-26 125 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