0

I am using an external library in my project which is being build in an ARC environment. As per the library the socket object gets deallocated only when the retain count=0. As far as I know its not liable to use retain count in ARC but I am forced to remove all the reference of the socket object which is not possible in my project. How can I resolve this issue? A gist of code issue is below:

-(void)callConnect{
   for(int i = 0; i<[userArray count];i++){
     [self connect:(NSString*)[userArray objectAtIndex:i]];
   }
}
-(void)connect:(NSString *)username{
    RTMPCLient *socket = [[RTMPClient alloc] init];
    BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket];
    NSMutableDictionary *stream = [NSMutableDictionary dictionaryWithObject:stream forKey:username];
}
-(void)disconnect{
    for(int i = 0; i<[userArray count];i++){
      [stream objectForKey:[NSString stringWithFormat:@"%@",[userArray objectAtIndex:i]]] = nil; //error on this line
    BroadCastClient *tempStream = [stream objectForKey:[userArray objectAtIndex:i]];
    tempStream = nil;
   }  
}

I am trying to make the stream object nil which gives an error. Cannot save it another variable as it increases the references of socket object.By making the tempStream nil doesn't affect the original instance created. I want to remove the reference of socket object from stream in the disconnect method. How can I do so?

user2955351
  • 273
  • 4
  • 18
  • What error do you have? – Avt Feb 25 '14 at 08:26
  • I have mentioned the error. But the main issue is I cannot disconnect until all references are removed – user2955351 Feb 25 '14 at 08:27
  • 1
    *As far as I know its not liable to use retain count in ARC*. No, it is NEVER liable. http://whentouseretaincount.com – vikingosegundo Feb 25 '14 at 08:39
  • This code can't even compile. In `connect:` there are two variables named `stream`. – DarkDust Feb 25 '14 at 09:00
  • So, is `stream` supposed to be an instance variable? A local variable? What's the point of reading but not using a value into `tempStream`? `[stream objectAtIndex:[userArray objectAtIndex:i]]` also looks wrong as `[userArray objectAtIndex:i]` cannot return an `NSUInteger`, it could return a `NSNumber`, though. But in `callConnect` you cast it to a `NSString`. So, what kind of elements do you have in `userArray`? – DarkDust Feb 25 '14 at 09:10
  • as I am getting error in the line above it,storing it in tempStream just to make the stream instance nil. no other purpose – user2955351 Feb 25 '14 at 09:12
  • userArray as string elements – user2955351 Feb 25 '14 at 09:13
  • _What_ error do you get? You're just not precise enough. Provide as much information and details as possible! What is it that you really want to accomplish? I have a hard time understanding what you're trying to do. – DarkDust Feb 25 '14 at 09:14
  • @DarkDust i had made some mistake its [stream objectAtIndex:[userArray objectForKey:i]]; – user2955351 Feb 25 '14 at 09:14
  • @DarkDust I am getting error on this line ` [stream objectForKey:[NSString stringWithFormat:@"%@",[userArray objectAtIndex:i]]] = nil; //error on this line` but the main issue is to remove all references of the instances of RTMPClient – user2955351 Feb 25 '14 at 09:16

3 Answers3

0

IN ARC, you have to just make the objects to nil to maintain RC. So you can do it in the following way.

-(void)disconnect{
  socket = nil;
  stream = nil;
  stream = nil;
}

-(void)connect:(NSString *)username{ 
   if (socket != nil )
      socket = nil;
   RTMPCLient *socket = [[RTMPClient alloc] init];

   if (stream != nil ) 
       stream = nil;
   BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket];

   NSMutableDictionary *stream = [NSMutableDictionary dictionaryWithObject:stream forKey:username]; // Make it using alloc...then you must use nil only
}
Samkit Jain
  • 2,523
  • 16
  • 33
  • sorry .. is disconnect? – user2955351 Feb 25 '14 at 08:27
  • Make alloc in the I have written....and also in disconnect you can remove objects..but once you are making dictionary with alloc – Samkit Jain Feb 25 '14 at 08:32
  • 2
    You want to read up on Apple's `goto fail;` bug to understand why your `if` constructs are bad. They're also unnecessary: `socket` and `stream` get assigned new instances, no matter what. In that case an old instance would get released. So there is no need to assign `nil` to the variables first. Also, there is no need to assign `nil` to `stream` twice in `disconnect`. You're defining two local variables `stream` of differing types (won't compile). since there seems to be an instance variable of the same name, a local variable of that name would shadow the instance variable. Very sloppy! – DarkDust Feb 25 '14 at 08:53
  • I see having `stream` twice was in the OPs code already. But then your access to `socket` and `stream` would be prior to their definition?! This code is totally b0rken. – DarkDust Feb 25 '14 at 09:02
  • @DarkDust Can u suggest a better solution? – user2955351 Feb 25 '14 at 09:09
  • @SamkitJain I want to preserve the previous instances too..so cant make them nil. – user2955351 Feb 25 '14 at 09:10
0

ARC will put the invisible release message in your code (in connect), but the array will have strong reference on them, so they will stay in memory. All you have to do in disconnect remove all the objects from your collection ([stream removeAllObjects] and [userArray removeAllObjects]) and the collection will release them.

UPDATE:
By following your code I see the following:
In this code you are creating an instance of BroadCastClient and adding it to NSDictionnary (stream), but NSDictionary has no reference to it, so it will be deallocated after the method call

-(void)callConnect{
   for(int i = 0; i<[userArray count];i++){
     [self connect:(NSString*)[userArray objectAtIndex:i]];
   }
}
-(void)connect:(NSString *)username{
    RTMPCLient *socket = [[RTMPClient alloc] init];
    BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket];
    NSMutableDictionary *stream = [NSMutableDictionary dictionaryWithObject:stream forKey:username];
}

Now here the disconnect stream dictionary (I don't know what is this object, because in your code I don't see any creating or adding to it) the object BroadCastClient is retained by the dictionary, so just removing this object from the dictionary will free it from memory (assuming you have no other strong reference to it)

-(void)disconnect{
    for(int i = 0; i<[userArray count];i++){
      [stream objectForKey:[NSString stringWithFormat:@"%@",[userArray objectAtIndex:i]]] = nil; //error on this line
    BroadCastClient *tempStream = [stream objectForKey:[userArray objectAtIndex:i]];
    tempStream = nil;
   }  
}

I would recommend some refactoring for your code, but before that please have some time to read this guid: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/memorymgmt/Articles/mmPractical.html

Basheer_CAD
  • 4,908
  • 24
  • 36
  • In disconnect you can remove objects..but once you are making dictionary with alloc. – Samkit Jain Feb 25 '14 at 08:33
  • Removing all object will guaranty that the collections released them. From apple documentations https://developer.apple.com/library/mac/documentation/cocoa/conceptual/memorymgmt/Articles/mmPractical.html – Basheer_CAD Feb 25 '14 at 08:36
  • @SamkitJain[stream removeAllObjects] will remove the references of stream. Will it remove the references of socket? Didn't get the other half of your comment – user2955351 Feb 25 '14 at 09:20
  • Yes, @user2955351, need to make some refactoring in his code, he needs a property with strong reference on his "stream" and "socket", plus using the code that i have provided – Basheer_CAD Feb 25 '14 at 09:24
  • If socket and stream obj i.e BroadCastClient obj are strong property then will i be able to remove the references of socket from dictionary stream ? – user2955351 Feb 25 '14 at 09:29
  • Yes, because you have a reference on them. I think thats what you need to achieve in your question, right ? – Basheer_CAD Feb 25 '14 at 09:30
  • @Basheer_CAD can u please refer the answer by Dark Dust and comment the on the query that I have posted there ? – user2955351 Feb 25 '14 at 09:42
  • @Basheer_CAD how can I deallocate instances of BroadCastClient? from disconnect method? – user2955351 Feb 25 '14 at 09:43
  • 1
    Lot's of problems here as well: `connect:` won't compile, `disconnect` won't compile either (`= nil;`). `tempStream` is unnecessary and the objects don't actually get removed from the `stream` dictionary. The `[NSString stringWithFormat:@"%@", ...]` isn't necessary either (assuming the `userArray` contains `NSString` instances, as `callConnect` suggests). – DarkDust Feb 25 '14 at 10:01
  • Yes, I agree with you. Thats why I recommend reading apple guid "Advanced memory management", because I just answered his question. If the question was what is bad with my code then the answer would be different :) @DarkDust – Basheer_CAD Feb 25 '14 at 10:04
0

It looks like stream is an instance variable of type NSMutableDictionary *. So if you want to remove the references in your stream dictionary, you could do it like this:

- (void)disconnect {
    for (int i = 0; i<[userArray count]; i++) {
      [stream removeObjectForKey:[userArray objectAtIndex:i]];
   }  
}

// Alternative version using Fast Enumeration:

- (void)disconnect {
    for (id key in userArray) {
        [stream removeObjectForKey:key];
    }
}

But if all you want to do is remove all references from stream, simply do:

- (void)disconnect {
   [stream removeAllObjects];
}
DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • I want to remove reference of socket from stream dictionary as well as BroadCastClient object i.e is initialized as BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket]; Will the above suggestion help in this case? – user2955351 Feb 25 '14 at 09:24
  • I don't know since your `connect:` method won't even compile and isn't even writing to the `stream` instance variable. My guess is that you're doing it like this: the `stream` _instance variable_ (a mutable dictionary) has objects of type `BroadCastClient`. These in turn have a reference to an `RTMPCLient` instance. As long as nobody else has a reference to these `RTMPCLient` instances, they will get deallocated once the `BroadCastClient` that owns it gets deallocated. So assuming that you don't have any references to your `BroadCastClient` instances outside of `stream`: yes, this will help. – DarkDust Feb 25 '14 at 09:28
  • It's hard to tell, though, as you simply haven't provided us with all the details needed to correctly analyze your problem. Next time, please provide more (and correct) details. It's in your own interest, after all :-) – DarkDust Feb 25 '14 at 09:30
  • ok, as of now I ll try to remove the references of BroadCastClient obj n then remove them of NSMutableStream – user2955351 Feb 25 '14 at 09:30
  • I can remove references of BroadCastClient *stream but how can I make this stream object as nil? deallocating it will only remove its reference to socket.. I am stuck at this point – user2955351 Feb 25 '14 at 09:33
  • What more details would be required for this query? – user2955351 Feb 25 '14 at 09:34
  • You mentioned that deallocating BroadCastClient instance will remove reference from socket obj. How can I deallocate the instance in disconnect method? – user2955351 Feb 25 '14 at 09:40
  • @Basheer_CAD can u help with this ? – user2955351 Feb 25 '14 at 09:41
  • @user2955351: I don't understand why you're obsessed with making things `nil`. Maybe you have trouble with understanding this: If you have code like this: `Foo *alpha = [[Foo alloc] init]; Bar *beta = [[Bar alloc] initWithFoo:alpha]; [myDictionary setObject:beta forKey:@"aKey"];` and you want "alpha" do get deallocated, you simply need to do `[myDictionary removeObjectForKey:@"aKey"];`. That would deallocate `beta` and by extension `alpha` (assuming that `beta` stored a reference to `alpha`). – DarkDust Feb 25 '14 at 09:47
  • I was not sure if [myDictionary removeAllObjects] would deallocate all instances of BroadCastClient thats why wanted to make it nil. Will try if u say so. Should I define BroasCastClient and RTMPClient instances as strong property or ivar ? – user2955351 Feb 25 '14 at 09:55
  • Neither! You allocate them in local variables, then put your `BroadCastClient` instance into your dictionary (`streams` ?). _That dictionary_ should be an ivar or property (it depends on whether anyone outside of you class should get access to that dictionary; go for an ivar if you can). – DarkDust Feb 25 '14 at 09:57