Push-Nachrichten von MacTechNews.de
Würden Sie gerne aktuelle Nachrichten aus der Apple-Welt direkt über Push-Nachrichten erhalten?
Forum>Entwickler>connectionDidFinishLoading never Invoked

connectionDidFinishLoading never Invoked

Christoph_M
Christoph_M09.01.1116:58
Moin,

ich bin gerade dabei mich in Objective-C und Cocoa einzuarbeiten und wollte als ersten Versuch ein Javaprogramm welches ich letztens kurz geschrieben hatte übertragen.
Ziel ist es menütlich im Hintergrund eine URL aufzurufen (DNS Update API von regfish) und das Resultat in ein NSTextField zu schreiben.

Der Ablauf ist eigentlich ganz einfach:
1) Button wird gedrückt pushButton wird ausgeführt, dort steht:
[self performSelectorInBackground:@selector(doTheJob) withObject:nil];

2) Der Code von doTheJob ist:
- (void)doTheJob {
    NSLog(@"doTheJob: start");
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    
    [progressIndicator setIndeterminate: true];
    [progressIndicator startAnimation: self];
        
    // URL Bauen
    NSString* adresse = @"http://www.google.com";
    NSLog(@"Adresse: %@",adresse);
        
    // Request zusammenbauen mit self als delegate
    responseData = [[NSMutableData data] retain];
    baseURL = [[NSURL URLWithString:adresse] retain];
    NSURLRequest *request =
    [NSURLRequest requestWithURL:[NSURL URLWithString:adresse]];
    [[NSURLConnection alloc] initWithRequest:request delegate:self];
    
    [pool release];
    NSLog(@"doTheJob: ende");
    
}

3) Für die NSURLConnection sind noch entsprechenden Methoden implementiert worden, da self als Delegate angegeben wurde:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"connection1");
    [responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSLog(@"connection2");
    [responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"connection3");
    [[NSAlert alertWithError:error] runModal];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // Once this method is invoked, "responseData" contains the complete result
    NSLog(@"connectionDidFinishLoading");
    NSString *resultat = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
    [logfield setStringValue:resultat];
    [progressIndicator setIndeterminate: false];
    [progressIndicator stopAnimation: self];
}

Das Problem ist aber, dass keine dieser Methoden jemals aufgerufen wird.

Entsprechend sieht der Log folgendermaßen aus:
[Session started at 2011-01-09 16:57:37 +0100.]
2011-01-09 16:57:38.892 Regfish DynDNS Updater[18641:903] Start gedrückt
2011-01-09 16:57:38.894 Regfish DynDNS Updater[18641:4a03] doTheJob: start
2011-01-09 16:57:38.913 Regfish DynDNS Updater[18641:4a03] Adresse: http://www.google.com
2011-01-09 16:57:38.916 Regfish DynDNS Updater[18641:4a03] doTheJob: ende

Hoffe jemand hier kann mir erklären, warum die in Schritt 3 genannten Methoden die aufgerufen werden. Die Internetverbindung steht natürlich und DNS funktioniert auch.

Danke schonmal und Grüße,
Christoph
0

Kommentare

Christoph_M
Christoph_M09.01.1122:44
Durch ein wenig Trial&Error konnte ich den Fehler eingrenzen, verstehen tue ich ihn aber nicht:

die Methode doTheJob wird ja in der Methode
- (IBAction)button:(NSButton *)sender {
    [self performSelectorInBackground:@selector(doTheJob) withObject:sender];
}
ausgeführt.

Hier liegt der Hund begraben. Wenn ich den Code der Methode doTheJob in die obige Methode rein copy-paste, dann funktioniert die NSURLConnection (= Ergebnis kommt an, connectionDidFinishLoading wird aufgerufen).

Wo ist das Problem? Wieso kann ich den Code nicht in eine seperate Methode auslagern um diese dann in einem eigenen Thread auszuführen? Das ist nötig weil die Methode button in der Zeit immernoch reagieren können muss.

Hoffe auf hilfreichen Input,
danke und Grüße
Christoph

p.s. wenn ich in meiner Beschreibung Fachbegriffe wie Methoden und Selektoren durcheinander bringe, dann bitte kurz drauf hinweisen. Aus Java kenne ich leider nur ersteres, möchte die Begriffe aber trotzdem möglichst korrekt verwenden.
0
Marcel Bresink13.01.1119:35
Ich sehe zwei Probleme: Zum einen wird "doTheJob" mit einem Parameter "sender" aufgerufen, obwohl die Methode so gar nicht definiert ist. Es sollte

- (void) doTheJob:(id) sender

beziehungsweise @selector(doTheJob:) heißen.

Zum anderen befindet sich im zweiten Thread kein RunLoop-Objekt (NSRunLoop). Deshalb ist dieser Thread nicht in der Lage, auf asynchrone Ereignisse wie z.B. eintreffende HTML-Daten zu reagieren.

Ist es wirklich nötig, das multi-threaded zu programmieren? Wenn der Button sofort wieder bereit werden soll, wäre eine sehr viel einfachere Lösung, ein

[self performSelector: @selector(doTheJob:) withObject: self afterDelay: 0.0];

zu verwenden. Dann wird die "Asynchronität" einfach in der normalen RunLoop miterledigt.
0
Duck Dodgers13.01.1120:34
Also wie Marcel sagt, ist da wohl ein Tippfehler? Mit oder ohne Argument? doTheJob oder doTheJob:(id)arg ?
Christoph_M
1) Button wird gedrückt pushButton wird ausgeführt, dort steht:
[self performSelectorInBackground:@selector(doTheJob) withObject:nil];
Christoph_M
die Methode doTheJob wird ja in der Methode
- (IBAction)button:(NSButton *)sender {
    [self performSelectorInBackground:@selector(doTheJob) withObject:sender];
}

Ich würde mal sagen, dass Problem liegt hier:
Christoph_M
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Die Methode wird ja abgearbeitet, also anscheinend gibts ein Problem mit NSURLConnection. Du solltest mal überprüfen, ob die Verbindung überhaupt zustande kommt.

Vielleicht liegt es aber auch daran, dass du versuchst diese Methode in einem Thread auszuführen und sobald die Methode beendet ist läuft der Thread ja nicht weiter und dir geht alles flöten, dann kann dir ja auch keine Verbindung zustande kommen!
0

Kommentieren

Diese Diskussion ist bereits mehr als 3 Monate alt und kann daher nicht mehr kommentiert werden.