Closed kaalita closed 12 years ago
Thanks! Just a few minor issues...
Updated the code as you suggested. This also includes a fix for another mistake in my original code (after an error occured, the error property was never set to nil again, when subsequent requests were successful).
Hm, this method works fine with all sorts of failed requests that return at least some kind of response. But I just simulated a request timeout and the error property wasn't changed to the timeout error. It looks like the -operation:willCompleteWithError: implementation in the CouchQuery class isn't called at all, it only calls the -operation:willCompleteWithError: implemention of the CouchResource class.
To catch also the timeout error I could of course move the error property to the CouchResource class, but not sure whether this is the best way to do it.
It looks like the -operation:willCompleteWithError: implementation in the CouchQuery class isn't called at all, it only calls the -operation:willCompleteWithError: implemention of the CouchResource class.
Can you explain in more detail? CouchQuery overrides that method, so I don't see a way for the CouchResource implementation to be called without going through the CouchQuery override.
RESTOperation treats HTTP error statuses and socket-level errors the same way; they both call -completedWithError:, which in turn calls the owning resource's -operation:willCompleteWithError:.
For my test I made all requests to xyz.iriscouch.com time out. I started my app which contains a UITableView with a CouchUITableSource. When I create the CouchLiveQuery with the asLiveQuery method, this happens:
(*) I added comments to all the operation:willCompleteWithError: methods to see which where called and to find out why the error isn't stored in the error property.
the method seems to create the CouchLiveQuery synchronously, because it doesn't return until the timeout occurs
I don't think it does — I can't see any place in that code path that will block. And I ran the TouchDB iOS demo and looked at all the calls to -[RESTOperation wait], and none were invoked on a view. Can you pause the app while it's blocked in the synchronous call and show me the backtrace (use the 'bt' debugger command)?
the operation:willCompleteWithError: is called, but not on CouchQuery, but on CouchResource (*)
Please set a breakpoint in the CouchResource method and send me the backtrace when it was hit. I think it must be invoked from the 'super' call in the CouchQuery method.
To the first point: Oh, you were right, it's not the asLiveQuery method that doesn't return immediately, it's the setQuery method of the CouchUITableSource in the same code line: self.query = [query asLiveQuery];
(lldb) bt
mach_msg_trap + 10, stop reason = signal SIGSTOP frame #0: 0x94271c22 libsystem_kernel.dylib
mach_msg_trap + 10
frame #1: 0x942711f6 libsystem_kernel.dylibmach_msg + 70 frame #2: 0x0237f10a CoreFoundation
CFRunLoopServiceMachPort + 186
frame #3: 0x022e25d5 CoreFoundation__CFRunLoopRun + 1445 frame #4: 0x022e1d84 CoreFoundation
CFRunLoopRunSpecific + 212
frame #5: 0x022e1c9b CoreFoundationCFRunLoopRunInMode + 123 frame #6: 0x01c1f40f Foundation
-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 300
frame #7: 0x001b36c8 Lingya-[RESTOperation wait] + 296 at RESTOperation.m:186 frame #8: 0x001b4ce3 Lingya
-[RESTOperation responseBody] + 51 at RESTOperation.m:392
frame #9: 0x001bcbf2 Lingya-[CouchDatabase lastSequenceNumber] + 114 at CouchDatabase.m:370 frame #10: 0x001bd585 Lingya
-[CouchDatabase setTracksChanges:] + 165 at CouchDatabase.m:471
frame #11: 0x001acd0d Lingya-[CouchLiveQuery start] + 157 at CouchQuery.m:247 frame #12: 0x001acbb6 Lingya
-[CouchLiveQuery rows] + 70 at CouchQuery.m:231
frame #13: 0x001bdddc Lingya-[CouchUITableSource reloadFromQuery] + 60 at CouchUITableSource.m:105 frame #14: 0x001bdd95 Lingya
-[CouchUITableSource setQuery:] + 277 at CouchUITableSource.m:99
frame #15: 0x0009523c Lingya-[NewsfeedDatasource init] + 620 at NewsfeedDatasource.m:40 frame #16: 0x0001aaa5 Lingya
-[NewsfeedViewController viewDidLoad] + 421 at NewsfeedViewController.m:63
frame #17: 0x013a0a1e UIKit-[UIViewController view] + 184 frame #18: 0x0139ffec UIKit
-[UIViewController nextResponder] + 34
frame #19: 0x013c6f1d UIKit-[UIResponder _containsResponder:] + 40 frame #20: 0x013b11cb UIKit
-[UINavigationController defaultFirstResponder] + 83
frame #21: 0x013c7e59 UIKit-[UIResponder(Internal) _deepestDefaultFirstResponderMatching:] + 59 frame #22: 0x013c7e76 UIKit
-[UIResponder(Internal) _deepestDefaultFirstResponderMatching:] + 88
frame #23: 0x013c7e76 UIKit-[UIResponder(Internal) _deepestDefaultFirstResponderMatching:] + 88 frame #24: 0x013c7f3a UIKit
-[UIResponder(Internal) _promoteDeepestDefaultFirstResponder] + 181
frame #25: 0x013066f5 UIKit-[UIWindow makeKeyWindow] + 401 frame #26: 0x0130673c UIKit
-[UIWindow makeKeyAndVisible] + 53
frame #27: 0x00019cf3 Lingya-[EmphrasesAppDelegate application:didFinishLaunchingWithOptions:] + 979 at EmphrasesAppDelegate.m:86 frame #28: 0x012d7386 UIKit
-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1292
frame #29: 0x012d8274 UIKit-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 524 frame #30: 0x012e7183 UIKit
-[UIApplication handleEvent:withNewEvent:] + 1027
frame #31: 0x012e7c38 UIKit-[UIApplication sendEvent:] + 68 frame #32: 0x012db634 UIKit
_UIApplicationHandleEvent + 8196
frame #33: 0x02b1fef5 GraphicsServicesPurpleEventCallback + 1274 frame #34: 0x0237f195 CoreFoundation
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION + 53
frame #35: 0x022e3ff2 CoreFoundation__CFRunLoopDoSource1 + 146 frame #36: 0x022e28da CoreFoundation
__CFRunLoopRun + 2218
frame #37: 0x022e1d84 CoreFoundationCFRunLoopRunSpecific + 212 frame #38: 0x022e1c9b CoreFoundation
CFRunLoopRunInMode + 123
frame #39: 0x012d7c65 UIKit-[UIApplication _run] + 576 frame #40: 0x012d9626 UIKit
UIApplicationMain + 1163
frame #41: 0x000197ed Lingyamain + 125 at main.m:14 frame #42: 0x000027e5 Lingya
start + 53Please set a breakpoint in the CouchResource method and send me the backtrace when it was hit. I think it must be invoked from the 'super' call in the CouchQuery method.
Sorry, I would, but I can't get that to work :-( I added a symbolic breakpoint for the symbol: [CouchResource operation:willCompleteWithError:] but the breakpoint is never invoked.
I'm already googling for an answer, but until now nothing worked.
But this hack http://stackoverflow.com/a/9603733 might help out a little bit. I don't know how reliable this is, but at least it gave me now 3 times in a row the same result:
2012-07-03 19:38:12.695 Lingya[24106:11303] Stack = 1 2012-07-03 19:38:12.695 Lingya[24106:11303] Framework = Lingya 2012-07-03 19:38:12.695 Lingya[24106:11303] Memory address = 0x001b4678 2012-07-03 19:38:12.695 Lingya[24106:11303] Class caller = RESTOperation 2012-07-03 19:38:12.696 Lingya[24106:11303] Function caller = completedWithError: 2012-07-03 19:38:12.696 Lingya[24106:11303] Line caller = 920
When a timeout occurs, the method is called from RESTOperation, not from CouchQuery.
Re the timeout: your backtrace shows it's coming from setting the tracksChanges property of the database, which CouchUITableSource does so it can listen for changes. (Setting -tracksChanges gets the db's latest sequence number via a synchronous call — this could perhaps be fixed to be async.)
I'll review your pull request again — sorry for the delay, was stuck with a bunch of Couchbase Server tasks this week.
Readonly error property stores the error of the last request.