充当NSUrlConnection委托的NSObject实例似乎不是孤立的

时间:2011-11-03 15:53:08

标签: iphone objective-c ios nsurlconnection

首先发布这里,所以我希望它足够详细。

在开发Iphone应用程序时,我遇到了一些奇怪的行为。我的“WebserviceConnection”类的某个实例的成员变量似乎获得了我分配给同一类的另一个实例的值。

举例说明:这是我日志的摘录。我假设 0x000000是一个实例ID。第四个回答应为“< - :1”。

2011-11-03 16:25:13.227 Dashboard[540:707] ->: 1, <WebserviceConnection: 0x11f950>
2011-11-03 16:25:13.256 Dashboard[540:707] ->: 0, <WebserviceConnection: 0x323db0>
2011-11-03 16:25:15.318 Dashboard[540:707] <-: 0, <WebserviceConnection: 0x323db0>
2011-11-03 16:25:15.325 Dashboard[540:707] <-: 0, <WebserviceConnection: 0x11f950>

该类是NSUrlConnection委托,当两个连接同时打开时,它表现出这种行为。

此类:WebserviceConnection.h

(ConnectionType是枚举)

#import "WebserviceConnection.h"
#import "WebserviceUtility.h"

@implementation WebserviceConnection

BOOL isCanceled;
NSDictionary *result;
ConnectionType connectionType;
id <WebserviceConnectionDelegate> delegate;

- (id)initWithDelegate:(id)webServiceDelegate connectionType:(ConnectionType) type {
    delegate = webServiceDelegate;
    connectionType = type;
    isCanceled = NO;
    NSLog(@"->: %i, %@", connectionType, self);
    return self;
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    switch (connectionType) {
        case GetAllAlerts:
            result = [WebserviceUtility getJsonFromData:data]; 
            break;
        case GetServerAlerts:
            result = [WebserviceUtility getJsonFromData:data]; 
            break;
        case GetServers:
            result = [WebserviceUtility getJsonFromData:data]; 
            break;
        default:
            result = nil;
            break;
    }
}

- (void)displayErrorAlert {
    UIAlertView *errorMessage = [[UIAlertView alloc] initWithTitle:@"Fout" message:@"Verbinding met webservice niet mogelijk" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    [errorMessage show];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    if(!isCanceled) {
        @try {
            [delegate connection:connection ofType:connectionType didFinishWithError: [NSDictionary dictionaryWithObject:@"error" forKey:@"WebserverConnectionFailed"]];
        }
        @catch (NSException *e) {}
        @finally {}
        [self displayErrorAlert];
    }
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"<-: %i, %@", connectionType, self);
    if(!isCanceled) {
        [delegate connection:connection ofType:connectionType didFinishWithResult:result];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSURLCredential *credential = [WebserviceUtility getCredentials];
    if ([challenge previousFailureCount] == 0) {
        [[challenge sender] useCredential:credential
               forAuthenticationChallenge:challenge];
    }
    else {
        [delegate connection:connection ofType:connectionType didFinishWithError: [NSDictionary dictionaryWithObject:@"error" forKey:@"WebserverConnectionFailed"]];
        [self displayErrorAlert];

    }
}

- (void)delegateDidDealloc {
    NSLog(@"!!: %i, %@", connectionType, self);
    isCanceled = YES;
}

@end

像这样使用:

- (void) getAllAlerts {
    NSURLRequest *request = [WebserviceUtility getRequestForPath:@"/dashboard/DashboardAppleConnector.asmx/GetActiveAlerts"];
    webserviceConnection = [[WebserviceConnection alloc] initWithDelegate:self connectionType:GetAllAlerts];
    connection = [[NSURLConnection alloc] initWithRequest:request delegate: webserviceConnection];
}

当另一个具有自己的webserviceConnection实例的ViewController使用它的实例(类似于getAllAlerts)时,所有的都是pearshaped!

任何想法?

此致 伯特

2 个答案:

答案 0 :(得分:1)

定义块:

BOOL isCanceled;
NSDictionary *result;
ConnectionType connectionType;
id <WebserviceConnectionDelegate> delegate;

将这四个事物声明为全局变量,就好像它们不在@implementation块中一样。简单地将内容放在@implementation中并不会使它们成为对象的本地 - 它只是解释了所有后续方法实现所属的对象。

如果您不介意将实现细节放入头文件中,可以将它们移到@interface声明中,例如

@interface WebserviceConnection
{
    BOOL isCanceled;
    NSDictionary *result;
    ConnectionType connectionType;
    id <WebserviceConnectionDelegate> delegate;
}

// etc

@end

你可以通过一个类别将它们添加到你的类中,以牺牲一些重复语法为代价,将它们完全保留在实现内部,例如

#import "WebserviceConnection.h"
#import "WebserviceUtility.h"

@interface WebserviceConnection() // a category to add additional properties
@property (nonatomic, assign) BOOL isCanceled;
@property (nonatomic, retain) NSDictionary *result;
@property (nonatomic, assign) ConnectionType connectionType;
@property (nonatomic, assign) id <WebserviceConnectionDelegate> delegate;
@end

@implementation WebserviceConnection

// synthesising the properties also adds the named properties as instance variables
@synthesize isCanceled;
@synthesize result;
@synthesize connectionType;
@synthesize delegate;

- (id)initWithDelegate:(id)webServiceDelegate ... etc...

除此之外:一个名为getJsonFromData:的方法应该根据Cocoa命名约定返回一个非拥有引用,因为它不包含'new','alloc','retain'或'create'。如果你服从的话,会在代码中的result中留下一个悬空指针。

答案 1 :(得分:1)

看起来问题正在发生,因为你声明你的变量就像connectionType一样。如果您希望将它们声明为实例变量,则应将它们放在接口声明中:

@interface WebServiceConnection {
    BOOL isCanceled;
    NSDictionary *result;
    ConnectionType connectionType;
    id <WebserviceConnectionDelegate> delegate;
}
@end

通过在@implementation块中声明它们,您实际上是在创建全局变量,而不是实例变量。

有关详细信息,请参阅this SO post