1

ロケーションマネージャーを使用してロケーションデータを生成し、URLで送信してデータをダウンロードしています。初めてロケーションマネージャーを呼び出すと、現在の場所が正しく返され、現在の場所に基づいてURLからデータを取得できます。

ただし、現在の場所をもう一度取得しようとすると、EXC_BAD_EXCESSを受け取ります。

それを使ってデバッグしようとすると、メソッド内のゾンビとしてNSZombieEnabled表示されます。(以下のマークされたコードを参照)FirstViewController.recievedDatadidReceiveResponse

さらに掘り下げてみると、最初の接続を解放した後、不明な接続が確立され、receivedDataすでに解放されている接続にアクセスしようとしていることがわかりました。

ヘッダーファイル情報: `

#import <CoreLocation/CoreLocation.h>
define SECS_OLD_MAX 1
@interface FirstViewController : UIViewController<CLLocationManagerDelegate> {
    UIActivityIndicatorView *spinner;
    CLLocationManager *locationManager;
    CLLocation *startingPoint;
    UIButton *relocateMe;
    NSMutableData *receivedData;
    NSString *lat;
    NSString *lon;
}
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *spinner;
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) CLLocation *startingPoint;
@property (nonatomic, retain) IBOutlet UIButton *relocateMe;
@property (nonatomic, retain) NSMutableData *receivedData;
@property (nonatomic, retain) NSString *lat;
@property (nonatomic, retain) NSString *lon;

`

.mファイルコード:

//飼い葉桶を開始します:

   [spinner startAnimating];
**EDIT**************************ADDED IN THE AUTORELEASE POOL BY HIB********************************
    self.locationManager = [[[CLLocationManager alloc] init]autorelease];
    // Detecting the user device
    NSString *currentDevice =  [[UIDevice currentDevice] model];
    // if its iPhone then locate the current lattitude and longitude
    if([currentDevice isEqualToString:@"iPhone"] || [currentDevice isEqualToString:@"iPhone 3G"] || [currentDevice isEqualToString:@"iPhone 3G S"]){
        DLog(@"I have identified the device as an iPhone");
        if(locationManager.locationServicesEnabled == YES){
            DLog(@"ok now the location manager gets the property");
            locationManager.delegate = self;
            // This is the most important property to set for the manager. It ultimately determines how the manager will
            // attempt to acquire location and thus, the amount of power that will be consumed.
            locationManager.desiredAccuracy = kCLLocationAccuracyBest;
            // Once configured, the location manager must be "started".
            [locationManager startUpdatingLocation] ;
        }else {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oops!" 
                                                            message:@"Please enable location servies"
                                                           delegate:nil
                                                  cancelButtonTitle:@"OK" 
                                                  otherButtonTitles:nil];
            [alert show];
            [alert release];
        }
    }
    //if its iPod then fetch the city based restaurants
    else if([currentDevice isEqualToString:@"iPod touch"] || [currentDevice isEqualToString:@"iPod touch 2G"]){
    }
    else if([currentDevice isEqualToString:@"iPhone Simulator"]){
       //TechZen says: there appears to be some code missing here, not sure if its relevant
    }

//didupdatetolocationメソッド

  - (void)locationManager:(CLLocationManager *)manager
        didUpdateToLocation:(CLLocation *)newLocation
               fromLocation:(CLLocation *)oldLocation {
        // store the location as the "best effort"
        DLog(@"Lat = %g Long = %g",newLocation.coordinate.latitude,newLocation.coordinate.longitude);
        NSDate *eventDate = newLocation.timestamp; 
        NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
        DLog(@"NSTIME INTERVAL = %i",howRecent);
        //Is the event recent and accurate enough ?
        if (abs(howRecent) < SECS_OLD_MAX) {
            self.lat = [NSString stringWithFormat:@"%g",newLocation.coordinate.latitude];
            self.lon = [NSString stringWithFormat:@"%g",newLocation.coordinate.longitude];
            [[NSUserDefaults standardUserDefaults] setObject:lat forKey:@"LATITUDE"];
            [[NSUserDefaults standardUserDefaults] setObject:lon forKey:@"LONGITUDE"];
        DLog(@"inside Lat = %g Long = %g",newLocation.coordinate.latitude,newLocation.coordinate.longitude);
        self.startingPoint = newLocation;
        [locationManager stopUpdatingLocation];
**EDIT********************************REMOVED BY HIB******************************
        self.locationManager = nil; 
        [locationManager release];  
**EDIT********************************REMOVED BY HIB******************************

**ADDED BY HIB********************************************
        locationManager.delegate = nil; 
**ADDED BY HIB********************************************
        @try {
            //passing the parameter for more condition
            self.lat = [NSString stringWithFormat:@"%g",startingPoint.coordinate.latitude];
            self.lon = [NSString stringWithFormat:@"%g", startingPoint.coordinate.longitude];
            NSString *string2 = [[NSString alloc] initWithFormat:@"%@/Service.asmx/someMethod?lat1=%g&lon1=%g&recordSize=0"
                                 ,[[NSUserDefaults standardUserDefaults] stringForKey:@"textEntry_key"],startingPoint.coordinate.latitude,startingPoint.coordinate.longitude];
            NSURL *url = [[NSURL alloc] initWithString:string2];
            [string2 release];
            NSMutableURLRequest* request2=[NSMutableURLRequest requestWithURL:url];
            [request2 setHTTPMethod:@"GET"]; 
            [request2 setTimeoutInterval:25.0];
            [[NSURLCache sharedURLCache] setMemoryCapacity:0];
            [[NSURLCache sharedURLCache] setDiskCapacity:0];
            NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request2 delegate:self];
            if (theConnection) {
                receivedData = [[NSMutableData data]retain];
            } else {
                // inform the user that the download could not be made
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Sorry !"
                                                                message:@"The server is not avaialable \n Please try againa later" 
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
                [alert show];
                [spinner stopAnimating];
            }
            [url release];
        }
        @catch (NSException * e) {
        }
        @finally {
        }
    }
    }

//およびデリゲートメソッド

 #pragma mark -
    #pragma mark connection methods
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        // this method is called when the server has determined that it
        // has enough information to create the NSURLResponse
        // it can be called multiple times, for example in the case of a
        // redirect, so each time we reset the data.
        // receivedData is declared as a method instance elsewhere

    **************************************the zombie is here *********************************
        [receivedData setLength:0];
    *****************************************************************************************
    }
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        // append the new data to the receivedData
        // receivedData is declared as a method instance elsewhere
        [receivedData appendData:data];
    }
    - (void)connection:(NSURLConnection *)connection
      didFailWithError:(NSError *)error
    {
        [spinner stopAnimating];
        // release the connection, and the data object
        [connection release];
        // receivedData is declared as a method instance elsewhere
        [receivedData release];
        // inform the user
        DLog(@"Connection failed! Error - %@ %@",
              [error localizedDescription],
              [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
        // alert the user in the inter face.
        UIAlertView* alert = [[UIAlertView alloc]initWithTitle:@"Sorry !"
                                                       message:@"The server is not available.\n Please try again later."
                                                      delegate:nil
                                             cancelButtonTitle:@"OK" 
                                             otherButtonTitles:nil];
        [alert show];
        [alert release];
    }

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        // do something with the data
        // receivedData is declared as a method instance elsewhere
        DLog(@"Succeeded! Received %d bytes of data",[receivedData length]);
        [spinner stopAnimating];
        // release the connection, and the data object
        if(receivedData == nil)
        {
            UIAlertView* alert = [[UIAlertView alloc]initWithTitle:@"Sorry !" 
                                                           message:@"The server is not available.\n Please try again later or select city." 
                                                          delegate:nil 
                                                 cancelButtonTitle:@"OK" 
                                                 otherButtonTitles:nil];
            [alert show];
            [alert release];
            [spinner stopAnimating];
        }
        else
        {
        //just parse and use the data 
        }
        [connection release];
        [receivedData release];
        }

助けてください 。ハマった。

4

5 に答える 5

3

クラスプロパティに適切にアクセスできないという体系的な問題があります。self.propertyNameを使用してアクセサへの呼び出しを強制しない限り、プロパティは自動的に保持および解放されません。例えば:

[locationManager stopUpdatingLocation]; <-- direct access 
self.locationManager = nil; <-- access through generated accessor
[locationManager release]; <-- direct access again with release bypassing the automatic memory management

あなたが持っている必要があります:

[self.locationManager stopUpdatingLocation];
self.locationManager = nil;
//[locationManager release]; this line is now unneeded because the accessor handles it

とで同じ問題が発生しrecievedDataますstartingPoint。ほとんどの場合、合成されたアクセサーを使用する場合は、deallocに保持されているプロパティでreleaseを呼び出すだけで済みます。アクセサーを使用すると、ゾンビの問題が解決します。

どこでEXC_BAD_ACCESS発生するかわからないので明確に言うことはできませんが、存在しないオブジェクトにメッセージを送信するとエラーが発生することが多いため、プロパティアクセサーをバイパスして手動で解放すると、おそらくコードが発生している可能性があります。 nilledプロパティに送信します。

アクセスを修正し、それで問題が解決するかどうかを確認します。

Edit01:

TechZenの問題は50%削除されます。私のアプリケーションはデバッグモードでうまく動作しますが、ケーブルを抜いて再起動するとクラッシュします。問題は確かにロケーションマネージャにあります。しかし、ロケーションマネージャーの保持とリリースについては明確ではありません。手伝って頂けますか

私はそれを突き刺します。あなたの記憶管理のために:

  1. 常に self.locationManagerself-dot-propertyName表記を使用してアクセスし、生成されたアクセサーの保持/解放メカニズムを利用していることを確認してください。
  2. deallocメソッド以外のプロパティでreleaseを呼び出さないでください。セルフドット表記を使用し、プロパティを保持するように設定している場合、サポート終了リリースを除くすべてが自動的に処理されます。これには、プロパティをnilしたり、別のオブジェクトに設定したりする場合も含まれます。
  3. 疑わしい場合は、リリースしないでください。保持カウントが歪んでいるためにコード内のランダムなポイントで消えるオブジェクトによって引き起こされたバグを追跡するよりも、後でメモリリークを修正する方が簡単です。環境を学習するときにリークを防ぐために一生懸命努力することは、それが防ぐよりも多くの問題を引き起こす時期尚早の最適化の一形態です。

locationManager:didUpdateToLocation:fromLocation:メソッドでは、メソッドに渡されたlocationManagerを実際にクエリするのではなく、クラスのself.locationManagerプロパティをクエリすることに注意してください。これは問題になる場合とそうでない場合がありますが、渡されたマネージャーを使用して、更新されたマネージャーインスタンスを実際にクエリしていることを確認することをお勧めします。また、ロケーションマネージャを繰り返し破棄して再作成する必要はないと思います。一度初期化してそのままにしておくことができると思います(そのドキュメントを確認してください)。

プロパティ参照をクリーンアップして渡されたマネージャーを使用しても問題が解決しない場合は、クリーンアップされたコードを使用して新しい質問を投稿することをお勧めします。その時点で、合法的に新しい問題が発生し、さらに問題を特定するためにクリーンアップされたコードを確認する必要があります。

Edit02:

(新しいコードに基づく)

ここで「self.locationManager」プロパティを自動解放する必要はありません。

self.locationManager = [[[CLLocationManager alloc] init]autorelease];

自動リリースを使用するのは、オブジェクトを作成してクラス内で作成し、それを別のクラスに送信する場合のみです。クラスのプロパティを自動解放することはありません。

宣言されたプロパティを解放しようとするのをやめる必要があります。Deallocメソッドを除いて、retainで定義されたプロパティを解放することはありません。保持カウントを自動的に維持する、プロパティで生成されたアクセサを踏んでいます。

あなたはまだアクセサを一貫して使用していません。これ:

if(locationManager.locationServicesEnabled == YES){
    DLog(@"ok now the location manager gets the property");
    locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    // Once configured, the location manager must be "started".
    [locationManager startUpdatingLocation] ;

する必要があります:

if(self.locationManager.locationServicesEnabled == YES){
    DLog(@"ok now the location manager gets the property");
    self.locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    // Once configured, the location manager must be "started".
    [self.locationManager startUpdatingLocation] ;

この:

locationManager.delegate = nil;

する必要があります:

self.locationManager.delegate = nil; //<-- why are you doing this anyway? 

宣言されたすべてのプロパティへのすべての参照を追跡し、self.それぞれに添付する必要があります(使用していないように見えるプロパティカスタムアクセサーの内部を想定してください-この場合は適切です)。

あなたの問題は、self.locationManagerプロパティの保持を不必要にいじることであると強く思います。ロケーションマネージャがランダムに消える原因になっている可能性があります。

で渡されたマネージャーをまだ使用していません。使用するlocationManager:didUpdateToLocation:fromLocation:か、少なくとも渡されたマネージャーがと同じオブジェクトであることをテストすることをお勧めしますself.locationManager。単に。に置き換えself.locationManagerますmanager

于 2010-02-11T14:46:05.370 に答える
1

問題の原因は見つかりませんでしたが、リークがあります

self.locationManager = [[CLLocationManager alloc] init];

あなたが使用する必要があります

self.locationManager = [[[CLLocationManager alloc] init] autorelease];

代わりは。

編集: Charles Web Proxyをダウンロードし、作成している接続、取得する応答を確認してください。そうすれば、より良いアイデアが得られるかもしれません。

コメント後に編集:保持するように定義された自動生成されたアクセサープロパティは、渡されたオブジェクトを自動的に保持し、プロパティをnil/またはreleaseに設定すると解放します。つまり、ITSの仕事は減りますが、渡されたオブジェクトのメモリ管理を追跡するのはあなたの仕事です。したがって、はい、上記の初期コードにはリークがあります。ジョブを実行し、ALLOCATEDオブジェクトをRELEASE / AUTORELEASEする必要があります。この場合、このオブジェクトは次のようになります。[[CLLocationManager alloc] init].

編集: このコメントがどのように-1を取得できるかわかりません。シンプルなメモリ管理です。このスレッドの回答はすべて、これが正しい投稿であることに同意しています: iPhone:これはリークかどうか

于 2010-02-11T13:51:01.000 に答える
1

確かに間違っていると思う人もいます。receivedData開始する前に割り当てる必要がありますNSURLConnection。割り当て/初期化するとすぐにバックグラウンドでフォークするためreceivedData、後ではなく前に準備する必要があります。

于 2010-02-11T13:45:27.450 に答える
1

接続の最後にrecievedDataを解放していますが、ポインターをnilに設定していません。それでも、recievedDataがあった場所を指していることになります。

それ以外の

[recievedData release];

試す

self.recievedData = nil;

お役に立てば幸いです。

サム

于 2010-02-11T13:56:33.130 に答える
0

実際の問題は何だったのかわかりません。しかし、アップルのLocateMeの例を比較するとlocatiomManager.delegate = nil;、問題が完全に解決されていることがわかります。

于 2010-02-12T10:55:17.217 に答える