By the way, supporting 10.5 isn't necessarily a problem for using Blocks. PLBlocks is a viable plugin for Xcode on 10.5 that allows you to use blocks. I can attest that it is pretty stable and I would use it in production apps if I had to use 10.5 and needed blocks for something like this.
-Steven On Wed, Jan 20, 2010 at 1:32 PM, Carter R. Harrison <carterharri...@mac.com>wrote: > > On Jan 20, 2010, at 1:40 PM, Steven Degutis wrote: > > Recently I had the same issue you were having, sort of. And I came up with > a solution I really liked. > > When I was playing with Distributed Objects, I fell in love with the > abstract simplicity. However, it blocks and that's bad. It's even worse when > the server stops responding, because you could potentially have a 60 second > timeout before the single method will return. It's a potential disaster. > > So, I wrote an elegant compromise. Code is still written inline, no > callbacks or delegate messages needed. But, it requires Blocks (and thus > 10.6) to work. > > > Steven - this is a really interesting approach. I can see how this > basically achieves the same thing as all the callback methods, but does > allow the code to be written somewhat inline. Unfortunately I need to at > least support OS X 10.5 at this point. I definitely need to read-up on > blocks b/c I can see how they can be used to work around some tricky design > problems. > > > Essentially, I wrote some code on top of AsyncSocket (which is a brilliant > framework by the way) that allows me to wrap up ObjC messages as NSData, > send it across the server, and unpack it on the other side. The other side > then responds to the ObjC message as if it was called right inside the > application. (All this is thanks to NSInvocation's ability to introspect an > ObjC message, by the way). > > The problem came when I had to return values. As long as the return value > was void, this worked like a charm. But once I wanted to return an array of > strings or a number, I had to define a method in the sender's protocol to > receive such information. This is akin to your "thousands of delegate > messages" you would have to implement, as you stated. > > So, using Blocks and NSInvocation and AsyncSocket, I ended up writing code > that allows me to write code like this: > > > // protocol.h > > @protocol ServerProtocol > > - (NSNumber*) calculatePiAndKillTime:(NSNumber*)shouldKillTime; > > @end > > > // client.m > > - (void) someMethod { > id <ServerProtocol> server; > NSNumber *sure = [NSNumber numberWithBool:YES]; > [[server calculatePiAndKillTime: sure] > returnedValue:^(id value) { > // this will be called later on at some point > NSLog(@"pi = %@", value); > }] > } > > > // server.m > > - (NSNumber*) calculatePiAndKillTime:(NSNumber*)shouldKillTime { > if ([shouldKillTime boolValue]) > // synchronously watch some film > [self goWatchTheNewStarTrekFilmFrom2009]; > > return [NSNumber numberWithFloat: 3.14]; > } > > > > All methods sent to a destination's proxy are sent asynchronously. And, as > you can see, the return value of the method -calculatePiAndKillTime: is not > actually an NSNumber, but rather a proxy that waits for a response from the > destination. When the destination responds to the source with a return > value, the method -returnedValue: is called with the value. > > But that's only half of the coolness. > > The other half is that methods can simply return the value they want right > inside the method, no hacks necessary or anything by the programmer. In this > case, we just use this line of code: return [NSNumber numberWithFloat: > 3.14]; and then the NSNumber object is packaged up and sent back to the > source through the proxy, all automagically. > > The main downfall of this is that every argument and return value must be > an ObjC type, no scalars or structs or anything else will work with this > system. (Mike Ash explains pretty well on this blog why trying to support > those things can lead to some unfixable trickiness, which I just wanted to > avoid altogether.) > > If you can't support 10.6, then, this won't work. But hopefully you can > soon ;) > > Good luck. > > -Steven > > > > On Wed, Jan 20, 2010 at 11:39 AM, Carter R. Harrison < > carterharri...@mac.com> wrote: > >> I need some folks experienced with cocoa and socket programming to weigh >> in for me on some design problems I've been having. I'm designing an >> application that acts as a client in a client-server model. The client >> communicates with the server over the network by issuing a request and then >> receiving a response. Requests can only be issued one at a time, meaning >> that a request cannot be sent until a response from any outstanding request >> is first received. My application works in such a way that the it could >> request a handle to an object on the server and then use that handle in >> subsequent requests to retrieve additional information about the object. I >> see two ways of modeling the application - I've tried both and I'm not >> particularly happy with either. >> >> The first is to send a request, and then have the socket block until a >> response is received. This benefit to this model is that it is so much >> easier to write the higher level application code. The issue with this >> model is that over a slow network connection it can take a considerable >> amount of time for the response to come back from the server and while that >> is happening my CPU usage is through the roof b/c the thread is blocking. >> >> The second way is to send a request and then let the NSInputStream call a >> delegate method when the response data is available. The response data is >> then pushed up through my protocol stack and finally up to the higher level >> application code. The benefit to this method is that CPU usage is minimal >> due to the fact that I'm no longer blocking, but the downside is that the >> higher level application code is so much more difficult to write because I >> have to write about a thousand methods to act as a callback for each request >> in a series of requests. >> >> I've provided an example of how I see each working below. My first >> question is, is there other ways to design an application around this >> client-server model that I'm not thinking about? My 2nd question is, if >> there aren't other ways, how can I adapt either method that I have outlined >> to make it work a little bit better? >> >> As an example let's say the server knows about the following objects: >> >> 1. VendingMachine >> - An object that represents a vending machine. >> - A vending machine contains Soft Drink objects. >> 2. SoftDrink >> - Has the following properties: drink name, price, number of >> calories. >> >> If I use the blocking model, I could write my code like this. The code is >> simple to write but I'm forced to wait for the server to respond with >> information on pretty much every line of code. If the vending machine had >> enough soft drinks it could take a long time to iterate over each one and >> have the server respond with the drink's name of each drink. >> >> -(void)printDrinkNames >> { >> VendingMachine *machine = [server fetchVendingMachine]; >> NSArray *softDrinks = [machine getSoftDrinks]; >> for (int i = 0 ; i < softDrinks.count ; i++) >> { >> NSString *drinkName = [[softDrinks objectAtIndex:i] name]; >> NSLog(@"Found a drink named %@", drinkName); >> } >> } >> >> Likewise if I do the non-blocking approach I would have to have a method >> that gets called for each step in the process (see below). This model >> drives me crazy b/c the higher level application code is long, has tons of >> methods, and is just difficult to read and maintain. The example I have >> provided is simple enough to get the point across, but in reality some of >> the processes I'm trying to drive are much more complex and require numerous >> callback methods to pull off. >> >> -(void)printDrinkNames >> { >> [server fetchVendingMachineWithCallBackObject:self >> selector:@selector(didFetchVendingMachine:) >> } >> >> -(void)didFetchVendingMachine:(VendingMachine *)machine >> { >> [machine fetchSoftDrinksWithCallBackObject:self selector:@selector >> (didFetchSoftDrinks:)]; >> } >> >> -(void)didFetchSoftDrinks:(NSArray *)drinks >> { >> for (int i = 0 ; i < drinks.count ; i++) >> { >> SoftDrink *drink = [drinks objectAtIndex:i]; >> [drink fetchNameWithCallBackObject:self selector:@selector >> (didFetchDrinkName:)] >> } >> } >> >> -(void)didFetchDrinkName:(NSString *)name >> { >> NSLog(@"Drink name is %@", name); >> } >> >> _______________________________________________ >> >> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) >> >> Please do not post admin requests or moderator comments to the list. >> Contact the moderators at cocoa-dev-admins(at)lists.apple.com >> >> Help/Unsubscribe/Update your Subscription: >> >> http://lists.apple.com/mailman/options/cocoa-dev/steven.degutis%40gmail.com >> >> This email sent to steven.degu...@gmail.com >> > > > > -- > Steven Degutis > http://www.thoughtfultree.com/ > http://www.degutis.org/ > > > -- Steven Degutis http://www.thoughtfultree.com/ http://www.degutis.org/ _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com