Ссылка типа CFTypeRef является указателем на структуру, а имя ее типа обычно оканчивается на Ref (см. главу 3). Она обычно получается с помощью функции языка С, где предусмотрены функции для обращения с ней.

Эта ссылка похожа на объект, хотя и не является полноценным объектом Cocoa в языке Objective-C, и поэтому выделяемой для нее памятью следует управлять таким же образом, как и для объекта Cocoa. Тем не менее в механизме ARC отсутствует поддержка для такого управления памятью. Этот механизм управляет памятью, выделяемой для объектов Objective-C, но не для ссылок типа CFTypeRef. Поэтому управлять памятью, выделяемой для ссылок типа CFTypeRef, приходится вручную, даже если применяется механизм ARC. Пересекая своего рода мост между сторонами ссылок типа CFTypeRef и полноценных объектов Objective-C при обмене объектами, вы должны помочь механизму ARC уяснить его обязанности в отношении управления памятью.

Об ответственности за управление памятью, выделяемой для объектов Objective-C, напоминают имена некоторых методов (alloc, сору и retain), и это же относится к ссылкам типа CFTypeRef. Золотое правило в данном случае состоит в следующем: если вы получаете объект типа CFTypeRef с помощью функции, в имени которой содержится слово Create или Сору, то на вас возлагается ответственность за его освобождение из памяти. По умолчанию такой объект освобождается из памяти с помощью функции CFRelease (), но некоторые функции создания объектов применяются в паре со своими функциями освобождения из памяти.

В качестве примера ниже приведен фрагмент кода, взятый из одного из моих приложений. Этот код строго смоделирован по примеру кода от компании Apple, и в нем устанавливается цветовое пространство для базового образца, предназначенного для рисования.

- (void) addPattern: (CGContextRef) context color: (CGColorRef) incolor ( CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();

CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(baseSpace); CGContextSetFillColorSpace(context, patternSpace);

CGColorSpaceRelease(patternSpace);

 

CGColorSpaceRelease(baseSpace);

П ...

}

В данном примере не так важно назначение приведенного выше фрагмента кода, как то обстоятельство, что значения ссылок baseSpace и patternSpace относятся к типу CFTypeRef, а точнее — к типу CGColorSpaceRef. Эти ссылки получаются с помощью функций, в именах которых содержится слово Create, а следовательно, они освобождаются из памяти с помощью функции CGColorSpaceRelease (), эквивалентной методу release, после их применения.

Аналогично с помощью функции CFRetain () можно сохранить объект типа CFTypeRef, если есть опасение, что он может прекратить свое существование в то время, когда он все еще требуется. Однако после этого следует обязательно уравновесить данную операцию вызовом функции CFRelease ().

 

Сообщения можно посылать объекту Objective-C даже в том случае, если он пустой. В то же время функция CFRelease () не может принимать пустое значение (nil) в качестве своего аргумента. Поэтому убедитесь в том, что переменная типа CFTypeRef не содержит пустое значение, прежде чем освобождать ее.

 

Теперь обсудим, как же пересечь упомянутый выше мост между ссылками типа CFTypeRef и полноценными объектами Objective-C. Как пояснялось в главе 3, многие типы объектов из библиотеки Core Foundation свободно состыкованы подобными мостами с соответствующими типами объектов Cocoa. (Их перечень приведен в главе “Toll-Free Bridged Types” документации Core Foundation Design Concepts, предоставляемой компанией Apple.) Теоретически управление памятью остается таковым независимо от того, применяется ли оно в каркасе Core Foundation или среде Cocoa. Так, если получить ссылку типа CFStringRef с помощью функции Create () или Сору () и затем присвоить ее переменной экземпляра типа NSString, то отправка ей сообщения release через переменную экземпляра типа NSString окажется столь же полезной, как и вызов для нее функции CFRelease {). До появления механизма ARC управление памятью, выделяемой для данной ссылки, на этом завершалось.

Механизм ARC не позволяет поручить или изъять из его компетенции управление памятью, выделяемой для объекта, без явно указанной информации о том, как это управление должно осуществляться. Когда действует механизм ARC и объект начинает свое существование в результате получения его экземпляра, управление выделяемой для него памятью осуществляется механизмом ARC от начала и до конца существования этого объекта. Когда выполняется приведение типа объекта Objective к типу CFTypeRef, управление выделяемой для него памятью поручается компетенции механизма ARC. Однако механизм ARC не станет этого делать без дополнительной информации, поскольку неясны его обязанности по управлению памятью в данный момент. Аналогично, когда тип CFTypeRef приводится к типу объекта, управление памятью, выделяемой для готового экземпляра этого объекта, поручается компетенции механизма ARC, но опять же он не станет этого делать без дополнительной информации. Если же попытаться пересечь мост между ссылкой типа CFTypeRef и полноценным объектом, не предоставив механизму требующуюся ему информацию, компилятор выдаст сообщение об ошибке "Implicit conversion ... requires a bridged cast" (Неявное преобразование ... требуется стыковочное приведение типов).

Для правильного предоставления такой информации от вас потребуется чуть больше умственных усилий, но это даже хорошо, потому что вы сможете сообщить механизму ARC, что он должен сделать автоматически из того, вам иначе пришлось бы делать вручную. Например,

до появления механизма ARC вы могли получить ссылку типа CFStringRef с помощью функции Create () или Сору (), привести ее к типу NSString, а в дальнейшем послать ей сообщение release как объекту типа NSString. Если же действует механизм ARC, вы уже не сможете послать сообщение release, но в то же время можете настроить механизм ARC на те же самые действия: пересекая мост между ссылкой типа CFStringRef и полноценным объектом, передать эту ссылку с помощью функции CFBridgingRelease О . В результате будет получен идентификатор id, который может быть присвоен переменной экземпляра типа NSString. В конечном итоге механизм освободит этот идентификатор из памяти, чтобы уравновесить подсчет сохраняемых ссылок, первоначально установленный функцией Create () или Сору ().

Свободное стыкование типов может быть достигнуто тремя способами.

Приведение к типу bridge

Приведение выполняется к явно определяемому стыковочному типу bridge, наводящему мост между исходным и целевым типами данных. Это означает, что обязанности по управлению памятью не зависят ни от одной из сторон стыкования приводимых типов.

Ниже приведен пример (из главы 9), в котором осуществляется стыковочное приведение типа объекта Objective-C к типу ссылки CFTypeRef. Объект imageSource имеет тип NSURL и поэтому свободно стыкуется со ссылкой типа С FURL.

CGImageSourceRef src =

CGImageSourceCreateWithURL(( bridge CFURLRef)imageSource, nil);

Механизму ARC нужно сообщить его обязанности по управлению памятью. В данном случае они отсутствуют, а следовательно, объект imageSource типа NSURL будет и дальше существовать на стороне объектов Objective-C, и управление выделяемой для него памятью должно осуществляться механизмом ARC, как обычно. Объект imageSource предоставляется функции CGImageSourceCreateWithURL () лишь на мгновение, чтобы из него можно было сформировать ссылку типа CGImageSourceRef. С другой стороны, объект src типа CGImageSourceRef будет полностью существовать на стороне ссылок типа CFTypeRef, и поэтому управлять выделяемой для него памятью придется вручную, вызывая для него функцию CFRelease () после того, как он больше не нужен.

Функция CFBridgingRelease ()

В этом случае осуществляется стыкование ссылочного типа CFTypeRef с типом объекта Objective-C, а механизм ARC уведомляется, что управление памятью, выделяемой для этого объекта, не завершено, т.е. подсчет сохраняемых ссылок на стороне ссылочного типа CFTypeRef был увеличен (возможно, в результате формирования ссылки с помощью функции Create () или Сору ()). Поэтому на механизм ARC возлагается обязанность выполнить в конечном итоге соответствующее освобождение из памяти на стороне типа объекта. С другой стороны, можно выполнить приведение к стыковочному типу  bridge_transfer. Ниже представлен пример фрагмента кода из настоящего приложения, где он следует сразу же после фрагмента кода из предыдущего примера.

CFDictionaryRef resl = CGImageSourceCopyPropertiesAtlndex(src, 0, nil); NSDictionary* res = CFBridgingRelease(resl);

В данном примере функция CFRelease () вообще не будет вызвана для объекта resl типа CFDictionaryRef. Он был создан на стороне ссылочного типа CFTypeRef, поскольку для этого потребовалась функция CGImageSourceCopyPropertiesAtlndex (), что в конечном итоге привело к увеличению подсчета сохраняемых ссылок (вследствие копирования объекта). Стыкование типов произошло полностью и бесповоротно. В итоге был получен объект res языка Objective-C, который механизму ARC придется освободить из памяти, когда для этого настанет подходящий момент.

Функция CFBridgingRetain ()

Это совершенно противоположный случай по сравнению с применением функции CFBridgingRelease (). В данном случае происходит стыкование типа объекта Objective-C с ссылочным типом CFTypeRef. Механизм ARC уведомляется о необходимости оставить незавершенным управление памятью, выделяемой для данного объекта. Принимая во внимание увеличение подсчета сохраняемых ссылок на стороне типа объекта Objective-C, функцию CFRelease () придется вызвать вручную на стороне ссылочного типа CFTypeRef. С другой стороны, можно выполнить приведение к стыковочному типу  bridge_retained.

Как правило, объект Objective-C необязательно рассматривать как свободно состыкованный эквивалент типа CFTypeRef, чтобы обращаться с ним, используя функции С, позволяющие сделать то, чего нельзя сделать в противном случае. Теоретически на стороне ссылок типа CFTypeRef управление памятью не требуется, поскольку объект будет существовать на стороне объектов Objective-C. Однако в действительности он может и не существовать на стороне объектов Objective-C, поскольку он мог быть освобожден из памяти, и тогда ссылка типа CFTypeRef будет делаться на “мусор”. Во избежание этого следует вызвать функцию CFBridgingRetain () при стыковании типов, а по завершении работы на стороне ссылок типа CFTypeRef — вызвать функцию CFRelease (). С другой стороны, вполне возможно передать объект со стороны объектов Objective-C, вызвав функцию CFBridgingRetain (), а в дальнейшем возвратить его обратно с помощью функции CFBridgingRelease().

Иногда ссылку типа CFTypeRef требуется присвоить переменной id или параметру метода. Например, метод setContents : из класса CALayer ожидает получить параметр id, но его конкретным значением должна быть ссылка типа CGImageRef. Это вполне допустимо, поскольку, как упоминалось в главе 3, любая ссылка типа CFTypeRef свободно состыкована с параметром id. Тем не менее компилятор выдаст предупреждение, если не выполнить приведение к типу параметра id, и для этой цели может также потребоваться описатель стыковочного типа bridge, как показано ниже.

CGImageRef moi =11 что-нибудь одно или другое self.v.layer.contents = ( bridge idlmoi;

Если же ссылка типа CFTypeRef поступает из встроенного метода без промежуточного присваивания переменной, то описатель стыковочного типа bridge может и не потребоваться, как следует из приведенного ниже примера.

self.V.layer.contents = (id)[Ullmage imageNamed:@"moi"].CGImage;

Дело в том, что встроенный метод (например, метод экземпляра CGImage из класса Ullmage) сам предоставляет сведения о стыковании типов, вполне удовлетворяющие компилятор. Это видно из следующего заголовка метода CGImage:

- (CGImageRef)CGImage NS_RETURNS_INNER_POINTER;


 

 

 

Добавить комментарий