Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Howiieque

macrumors regular
Original poster
Feb 1, 2009
120
0
HI. I made an experiment about distributed object.

This exception handling is from a book:
Code:
/*- (void)connectionDidDie:(NSNotification *)aNotification
{
	NSConnection *deadConnection = [aNotification object];
	int i;
	for(i = [listOfClients count] - 1; i >= 0; i--)
	{
		id    currentClient = [listOfClients objectAtIndex:i];
		
		NS_DURING
		if([currentClient respondsToSelector:@selector(connectionForProxy)])
		{
			if(deadConnection == [currentClient connectionForProxy])
			{
				[listOfClients removeObjectAtIndex:i];
				NSLog(@"Removed client from client list.");
			}
		}
		NS_HANDLER
		[listOfClients removeObjectAtIndex:i];
		NSLog(@"Removed client from client list.");
		NS_ENDHANDLER
	}
}*/

I want to change it to use the for in loop.

Code:
- (void)connectionDidDie:(NSNotification *)aNotification {
	NSConnection *deadConnection=[aNotification object];
	for(id currentClient in listOfClients) {
		@try {
			if([currentClient respondsToSelector:@selector(connectionForProxy)]) {
				if([currentClient connectionForProxy]==deadConnection) {
					[listOfClients removeObject:currentClient];
					NSLog(@"Removed dead client: %@.", currentClient);
				}
			}
		}
		@catch (NSException * e) {
			int i=[listOfClients indexOfObject:currentClient];
			[listOfClients removeObjectAtIndex:i];
			//[listOfClients removeObject:currentClient];
			NSLog(@"%@. Removed dead client %@.", [e reason], currentClient);
		}
		@finally {
		}
	}
}

But [listOfClients removeObject:currentClient]; leads to an error. I can't figure it out. I tried to split it into two steps, but still had problems.

Another question is that [currentClient respondsToSelector:mad:selector(connectionForProxy)] never return YES. But it should. Testing it in gdb, I explicitly sent the message and it actually respond to connectionForProxy. Could someone give me an explanation?

I explicitly make it don't remove itself from the server list in AEClient.m , for the test of the block above.
Here's the whole codes:
 

Attachments

  • server.zip
    2.6 KB · Views: 54
  • client.zip
    1.8 KB · Views: 59

Guiyon

macrumors 6502a
Mar 19, 2008
771
4
Cambridge, MA
When using fast enumeration you are not allowed to modify the array you are enumerating over. Attempts to modify the source object will result in an exception being thrown. I'd suggest downloading Apple's "The Objective-C 2.0 Programming Language" PDF and looking over the chapter on FE, there are few useful tips/gotchas in there.
 

Howiieque

macrumors regular
Original poster
Feb 1, 2009
120
0
Thank you for your hint which to the point.
But why in the if test, it doesn't respond to connectionForProxy? I still haven't a clue.
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
Most likely respondsToSelector: is being sent to the actual client object, not the NSDistantObject.
 

Howiieque

macrumors regular
Original poster
Feb 1, 2009
120
0
Thanks for your reply, kainjow.
But I still don't quite understand. In the gdb, I typed print-object [currentClient connectionForProxy], and it returned(displayed) a connection object.
Although the author didn't give a lot of details about this code block, I think in this way it can handle the error. Or else the programme will never execute the inner if test.
Did the mechanism changed as time went by, or this example can't work properly? Is there some suggestion to fix it?
Could you give a little more explanation.
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
I guess the real question is, when will currentClient not respond to that selector when it's a valid object?
 

Howiieque

macrumors regular
Original poster
Feb 1, 2009
120
0
In general, it might work. But I still have some bugs can't track down.
1.
Code:
for (int i=[listOfClients count]-1; i>=0; i--) {
		id currentClient=[listOfClients objectAtIndex:i];
		@try {
			if([currentClient respondsToSelector:@selector(connectionForProxy)]) {
				if([currentClient connectionForProxy]==deadConnection) {
					[listOfClients removeObjectAtIndex:i];
					NSLog(@"Removed dead client.");
				}
			}
		}
		@catch (NSException * e) {
			[listOfClients removeObjectAtIndex:i];
			NSLog(@"error: %@. Removed dead client.", [e reason]);
		}
	}
case one. Connection works well. RespondsToSelector: is to be sent to the actual object, and NO returned.
case two. Connection is broken. Exception raises.
inner if has no chance to executes.

I have changed it to use NSSocketPort.
1. I launched one client, and then forced it exit.( maybe the [server removeMessageClient:self] was not invoked) In the terminal, it didn't show client was removed. Obviously, it can't handle the error. It seems that the connection was broken, and no notification was post.
2. Then I launched some more clients, and let them quit properly.( without the server relaunching) In this situation, it also failed to remove clients.
latest codes:
 

Attachments

  • client.zip
    2 KB · Views: 64
  • server.zip
    2.5 KB · Views: 58
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.