заставить сохранить счет в ARC

Я использую внешнюю библиотеку в своем проекте, который создается в среде ARC. В соответствии с библиотекой объект сокета освобождается только тогда, когда количество сохранений = 0. Насколько мне известно, в ARC нельзя использовать счетчик сохранения, но я вынужден удалить все ссылки на объект сокета, что невозможно в моем проекте. Как я могу решить эту проблему? Суть проблемы с кодом ниже:

-(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;
   }  
}

Я пытаюсь сделать объект потока нулевым, что дает ошибку. Невозможно сохранить другую переменную, поскольку она увеличивает количество ссылок на объект сокета. Создание tempStream nil не влияет на исходный созданный экземпляр. Я хочу удалить ссылку на объект сокета из потока в методе отключения. Как я могу это сделать?


person user2955351    schedule 25.02.2014    source источник
comment
Какая у вас ошибка?   -  person Avt    schedule 25.02.2014
comment
Я упомянул ошибку. Но главная проблема в том, что я не могу отключиться, пока не будут удалены все ссылки   -  person user2955351    schedule 25.02.2014
comment
Насколько мне известно, в ARC нельзя использовать счетчик сохранения. Нет, он НИКОГДА не несет ответственности. whentouseretaincount.com   -  person vikingosegundo    schedule 25.02.2014
comment
Этот код даже не компилируется. В connect: есть две переменные с именами stream.   -  person DarkDust    schedule 25.02.2014
comment
Итак, stream должна быть переменной экземпляра? Локальная переменная? Какой смысл читать, но не использовать значение в tempStream? [stream objectAtIndex:[userArray objectAtIndex:i]] также выглядит неправильно, так как [userArray objectAtIndex:i] не может вернуть NSUInteger, однако может вернуть NSNumber. Но в callConnect вы переводите его в NSString. Итак, какие элементы у вас есть в userArray?   -  person DarkDust    schedule 25.02.2014
comment
поскольку я получаю сообщение об ошибке в строке над ней, сохраняю ее в tempStream только для того, чтобы сделать экземпляр потока нулевым. никакой другой цели   -  person user2955351    schedule 25.02.2014
comment
userArray как строковые элементы   -  person user2955351    schedule 25.02.2014
comment
Какую ошибку вы получаете? Вы просто недостаточно точны. Предоставьте как можно больше информации и подробностей! Чего вы действительно хотите достичь? Мне трудно понять, что вы пытаетесь сделать.   -  person DarkDust    schedule 25.02.2014
comment
@DarkDust я сделал ошибку, это [stream objectAtIndex: [userArray objectForKey: i]];   -  person user2955351    schedule 25.02.2014
comment
@DarkDust Я получаю сообщение об ошибке в этой строке `[stream objectForKey:[NSString stringWithFormat:@%@,[userArray objectAtIndex:i]]] = nil; //ошибка в этой строке`, но основная проблема заключается в том, чтобы удалить все ссылки на экземпляры RTMPClient   -  person user2955351    schedule 25.02.2014


Ответы (3)


ARC поместит невидимое сообщение release в ваш код (при подключении), но array будет иметь сильную ссылку на них, поэтому они останутся в памяти. Все, что вам нужно сделать в disconnect, удалить все объекты из вашей коллекции ([stream removeAllObjects] и [userArray removeAllObjects]), и коллекция освободит их.

ОБНОВЛЕНИЕ:
Следуя вашему коду, я вижу следующее:
В этом коде вы создаете экземпляр BroadCastClient и добавляете его в NSDictionnary (stream), но NSDictionary не имеет на него ссылки. , поэтому он будет освобожден после вызова метода

-(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];
}

Теперь вот словарь disconnect stream (я не знаю что это за объект, т.к. в вашем коде я не вижу ни создания, ни добавления к нему) объект BroadCastClient сохраняется за словарем, так что просто удаляем этот объект из словаря освободит его из памяти (при условии, что у вас нет другой сильной ссылки на него)

-(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;
   }  
}

Я бы порекомендовал провести рефакторинг вашего кода, но перед этим, пожалуйста, прочтите это руководство: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/memorymgmt/Articles/mmPractical.html

person Basheer_CAD    schedule 25.02.2014
comment
При отключении вы можете удалять объекты... но как только вы создаете словарь с помощью alloc. - person Samkit Jain; 25.02.2014
comment
Удаление всех объектов гарантирует, что коллекции освободили их. Из документации Apple developer.apple.com/library /mac/documentation/cocoa/conceptual/ - person Basheer_CAD; 25.02.2014
comment
@SamkitJain[stream removeAllObjects] удалит ссылки на поток. Удалит ли он ссылки на сокет? Не понял второй половины вашего комментария - person user2955351; 25.02.2014
comment
Да, @ user2955351, нужно сделать рефакторинг в его коде, ему нужно свойство с сильной ссылкой на его поток и сокет, плюс использование кода, который я предоставил - person Basheer_CAD; 25.02.2014
comment
Если объект сокета и потока, то есть объект BroadCastClient, является сильным свойством, смогу ли я удалить ссылки на сокет из потока словаря? - person user2955351; 25.02.2014
comment
Да потому что у вас есть ссылка на них. Я думаю, это то, чего вам нужно добиться в своем вопросе, верно? - person Basheer_CAD; 25.02.2014
comment
@Basheer_CAD, не могли бы вы сослаться на ответ Dark Dust и прокомментировать запрос, который я там разместил? - person user2955351; 25.02.2014
comment
@Basheer_CAD, как я могу освободить экземпляры BroadCastClient? от метода отключения? - person user2955351; 25.02.2014
comment
Здесь тоже куча проблем: connect: не компилируется, disconnect тоже не компилируется (= nil;). tempStream не нужен, и объекты фактически не удаляются из словаря stream. [NSString stringWithFormat:@"%@", ...] также не нужен (при условии, что userArray содержит NSString экземпляров, как предполагает callConnect). - person DarkDust; 25.02.2014
comment
Да, я согласен с вами. Вот почему я рекомендую прочитать руководство Apple Advanced memory management, потому что я только что ответил на его вопрос. Если бы вопрос был в том, что плохого в моем коде, то ответ был бы другим :) @DarkDust - person Basheer_CAD; 25.02.2014

В ARC вам нужно просто обнулить объекты, чтобы поддерживать RC. Итак, вы можете сделать это следующим образом.

-(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
}
person Samkit Jain    schedule 25.02.2014
comment
извините .. отключение? - person user2955351; 25.02.2014
comment
Сделайте alloc в том, что я написал .... а также в отключении вы можете удалить объекты ... но как только вы создаете словарь с помощью alloc - person Samkit Jain; 25.02.2014
comment
Вы хотите прочитать об ошибке Apple goto fail;, чтобы понять, почему ваши конструкции if плохи. Они также не нужны: socket и stream назначаются новые экземпляры, несмотря ни на что. В этом случае старый экземпляр будет выпущен. Поэтому нет необходимости сначала присваивать переменным nil. Кроме того, нет необходимости дважды назначать nil на stream в disconnect. Вы определяете две локальные переменные stream разных типов (не компилируются). поскольку кажется, что существует переменная экземпляра с тем же именем, локальная переменная с таким именем будет затенять переменную экземпляра. Очень неаккуратно! - person DarkDust; 25.02.2014
comment
Я вижу, что stream дважды уже было в коде OP. Но тогда ваш доступ к socket и stream будет до их определения?! Этот код полностью b0rken. - person DarkDust; 25.02.2014
comment
@DarkDust Можете ли вы предложить лучшее решение? - person user2955351; 25.02.2014
comment
@SamkitJain Я тоже хочу сохранить предыдущие экземпляры ... поэтому не могу сделать их нулевыми. - person user2955351; 25.02.2014

Похоже, что stream — это переменная экземпляра типа NSMutableDictionary *. Итак, если вы хотите удалить ссылки в словаре stream, вы можете сделать это следующим образом:

- (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];
    }
}

Но если все, что вы хотите сделать, это удалить все ссылки из stream, просто выполните:

- (void)disconnect {
   [stream removeAllObjects];
}
person DarkDust    schedule 25.02.2014
comment
Я хочу удалить ссылку на сокет из потокового словаря, а также объект BroadCastClient, т.е. он инициализируется как BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket]; Поможет ли приведенное выше предложение в этом случае? - person user2955351; 25.02.2014
comment
Я не знаю, так как ваш метод connect: даже не компилируется и даже не записывает переменную экземпляра stream. Я предполагаю, что вы делаете это так: stream переменная экземпляра (изменяемый словарь) содержит объекты типа BroadCastClient. Они, в свою очередь, ссылаются на экземпляр RTMPCLient. Пока ни у кого нет ссылки на эти экземпляры RTMPCLient, они будут освобождены, как только будет освобожден экземпляр BroadCastClient, которому они принадлежат. Итак, если у вас нет ссылок на ваши экземпляры BroadCastClient за пределами stream: да, это поможет. - person DarkDust; 25.02.2014
comment
Однако трудно сказать, поскольку вы просто не предоставили нам все детали, необходимые для правильного анализа вашей проблемы. В следующий раз, пожалуйста, предоставьте больше (и правильную) информацию. Ведь это в ваших же интересах :-) - person DarkDust; 25.02.2014
comment
хорошо, сейчас я попытаюсь удалить ссылки на объект BroadCastClient, а затем удалю их из NSMutableStream. - person user2955351; 25.02.2014
comment
Я могу удалить ссылки BroadCastClient *stream, но как я могу сделать этот объект потока нулевым? освобождение его удалит только его ссылку на сокет. Я застрял на этом этапе - person user2955351; 25.02.2014
comment
Какие дополнительные детали потребуются для этого запроса? - person user2955351; 25.02.2014
comment
Вы упомянули, что освобождение экземпляра BroadCastClient удалит ссылку из объекта сокета. Как я могу освободить экземпляр в методе отключения? - person user2955351; 25.02.2014
comment
@Basheer_CAD можешь помочь с этим? - person user2955351; 25.02.2014
comment
@user2955351: Я не понимаю, почему вы так одержимы созданием вещей nil. Возможно, у вас есть проблемы с пониманием этого: если у вас есть такой код: Foo *alpha = [[Foo alloc] init]; Bar *beta = [[Bar alloc] initWithFoo:alpha]; [myDictionary setObject:beta forKey:@"aKey"];, и вы хотите, чтобы альфа-канал был освобожден, вам просто нужно сделать [myDictionary removeObjectForKey:@"aKey"];. Это освободит beta и, соответственно, alpha (при условии, что beta хранит ссылку на alpha). - person DarkDust; 25.02.2014
comment
Я не был уверен, что [myDictionary removeAllObjects] освободит все экземпляры BroadCastClient, поэтому хотел сделать это нулевым. Попробую, если скажешь. Должен ли я определять экземпляры BroasCastClient и RTMPClient как сильное свойство или ivar? - person user2955351; 25.02.2014
comment
Ни один! Вы размещаете их в локальных переменных, а затем помещаете свой экземпляр BroadCastClient в свой словарь (streams ?). Этот словарь должен быть ivar или свойством (это зависит от того, должен ли кто-либо за пределами вашего класса получить доступ к этому словарю; используйте ivar, если можете). - person DarkDust; 25.02.2014