iphone - How to properly use CFRelease in a context of captureStillImageAsynchronouslyFromConnection? -


not familiar memory management (only started on journey ios pampered arc), wanted girl , avoid leaking knew how to.

i capture still image video connection avfoundations capturestillimageasynchronouslyfromconnection, because want access image bytes. using core foundation , core graphics.

now bad access exception, when ios finishes capture block , tries release objects. must have overdone it.

i think have correctly:

  • released core graphics thingies create in correct sequence
  • neither retained nor released cvimagebufferref, because get-something , keeps original ownership
  • released copy of camera buffers metadata

edit: added optimization example code, curtesy of matthias bauch: there error in memory handling cfdatacreatewithbytesnocopy, cfrelease correctly now. not causing problem.

edit 2: matthias bauch, have been able narrow down called method. leaving else inside method, can make many snapshots without exceptions. added code of 1 below capturestillimageasynchronouslyfromconnection block calls it. continue in way find out wrong...

edit 3: inside called method, there 2 thingies released not responsible for. newacct, explained point point, have working method. post working code below.

capturestillimageasynchronouslyfromconnection block:

[[self imageoutput] capturestillimageasynchronouslyfromconnection:videoconnection completionhandler: ^(cmsamplebufferref imagesamplebuffer, nserror *error)     { // time stamp image capture          nsdate *timestamp = [nsdate date];           //get metadata in image          cfdictionaryref metadata = cmcopydictionaryofattachments(kcfallocatordefault,                                                                   imagesamplebuffer,                                                                   kcmattachmentmode_shouldpropagate);           // image reference          cvimagebufferref imagebuffer = cmsamplebuffergetimagebuffer(imagesamplebuffer);           // >>>>>>>>>> lock buffer address          cvpixelbufferlockbaseaddress(imagebuffer, 0);           //get information image          uint8_t *baseaddress = (uint8_t *)cvpixelbuffergetbaseaddress(imagebuffer);          size_t datasize = cvpixelbuffergetdatasize(imagebuffer);          size_t bytesperrow = cvpixelbuffergetbytesperrow(imagebuffer);          size_t width = cvpixelbuffergetwidth(imagebuffer);          size_t height = cvpixelbuffergetheight(imagebuffer);           // create pointer image data          cfdataref rawimagebytes = cfdatacreatewithbytesnocopy(kcfallocatordefault, baseaddress, datasize, kcfallocatornull);           // create color space current device          cgcolorspaceref colorspace = cgcolorspacecreatedevicergb();           //create bitmap context          cgcontextref newcontext = cgbitmapcontextcreate(baseaddress, width, height, 8, bytesperrow, colorspace, kcgbitmapbyteorder32little | kcgimagealphapremultipliedfirst);           // <<<<<<<<<< unlock buffer address          cvpixelbufferunlockbaseaddress(imagebuffer, 0);           // release core graphics object          cgcolorspacerelease(colorspace);           // create bitmap image data supplied context.          cgimageref newimage = cgbitmapcontextcreateimage(newcontext);           // release core graphics object          cgcontextrelease(newcontext);           bool saved = false;           // save cgimage tiff file objective-c          saved = [[self photoiocontroller] writetosubdirectorywithimageref:newimage orientation:[self orientation] timestamp: timestamp andmetadata: metadata];           // create uiimage (need change orientation of image image displayed correctly)          uiimage *image= [uiimage imagewithcgimage:newimage scale:1.0 orientation:uiimageorientationright];           // release core graphics object          cgimagerelease(newimage);           // set property display in stillimageviewcontroller          [self setstillimage: image];           // release core foundation object          cfrelease(rawimagebytes);           // release core foundation object          cfrelease(metadata);           // send notification camera container view controller when image has been taken          [[nsnotificationcenter defaultcenter] postnotificationname:kimagecapturedsuccessfully object:nil];     }]; 

the method seems cause exception:

  1. the parameters:

    • imageref cgimageref newimage = cgbitmapcontextcreateimage(newcontext);

    • orientation uideviceorientation uideviceorientationdidchangenotification, filtered minus ones not react to

    • timestamp nsdate *timestamp = [nsdate date];

    • metadata cfdictionaryref metadata = cmcopydictionaryofattachments(kcfallocatordefault, imagesamplebuffer, kcmattachmentmode_shouldpropagate);

  2. the code:

 -(bool) writetosubdirectorywithimageref: (cgimageref) imageref orientation: (uideviceorientation) orientation timestamp: (nsdate*) timestamp andmetadata: (cfdictionaryref) metadata  {     int imageorientation;      // according apple documentation on key kcgimagepropertyorientation,     /* http://developer.apple.com/library/ios/documentation/graphicsimaging/reference/cgimageproperties_reference/reference/reference.html#//apple_ref/doc/uid/tp40005103-ch3g-sw37 */     // values same in tiff , exif (so use libtiff definitions)      switch (orientation) {         case uideviceorientationportrait:             imageorientation = orientation_righttop;             break;         case uideviceorientationportraitupsidedown:             imageorientation = orientation_leftbot;             break;         case uideviceorientationlandscapeleft:             imageorientation = orientation_topleft;             break;         case uideviceorientationlandscaperight:             imageorientation = orientation_botright;             break;          default:             imageorientation = orientation_righttop;             break;     }      // mutable metadata copy     cfmutabledictionaryref mutablemetadata = cfdictionarycreatemutablecopy(kcfallocatordefault, cfdictionarygetcount(metadata), metadata);      // set key-value-pair     cfstringref mykey = kcgimagepropertyorientation; // not release!     cftyperef myvalue = cfnumbercreate(null, kcfnumberinttype, &imageorientation);      cfdictionaryreplacevalue(mutablemetadata, mykey, myvalue);      // time stamp     nsdateformatter *dateformatter = [[nsdateformatter alloc] init];     [dateformatter setdateformat:kdermaappphototimestampformat];     nsstring *stimestamp = [dateformatter stringfromdate:timestamp];      if ([self pathdermaappsubdirectory] != nil)     {         nsstring *filepath = [nsstring stringwithformat:(@"%@/%@%@"),[self pathdermaappsubdirectory],stimestamp,ktiffimagenameending];          // log file path         hlsloggerdebug(@"tiff image filepath = %@",filepath);          cfurlref url = (__bridge cfurlref)[nsurl fileurlwithpath:filepath isdirectory:no];         cgimagedestinationref destination = cgimagedestinationcreatewithurl(url, kuttypetiff, 1, null); // bridge: not release!          cgimagedestinationaddimage(destination, imageref, mutablemetadata);          if (cgimagedestinationfinalize(destination))         {             [self setpathlastimagesave:filepath];              // release core foundation object             cfrelease(destination);              // release core foundation object             cfrelease(mutablemetadata);              // release core foundation object             cfrelease(myvalue);              return true;         }         else         {             [self setpathlastimagesave:nil];             hlsloggerfatal(@"failed write image %@", filepath);         }          // release core foundation object         cfrelease(destination);     }      // release core foundation object     cfrelease(mutablemetadata);      // release core foundation object     cfrelease(myvalue);      return false; } 

the memory management of core foundation objects memory management of objective-c objects in cocoa -- if retained it, must release it; if didn't retain it, must not release it. naming conventions different. whereas "retaining" methods in cocoa have names starting alloc, retain, new, copy, , mutablecopy, in core foundation, it's if function name contains create or copy.

so in mind, let's @ code.

in first piece of code:

  • metadata: returned copy, it's retained, must release
  • imagebuffer: returned function get, not copy or create, it's not retained, must not release
  • rawimagebytes: returned create, it's retained, must release
  • colorspace: returned create, it's retained, must release
  • newcontext: returned create, it's retained, must release
  • newimage: returned create, it's retained, must release

in writetosubdirectorywithimageref::

  • imageref, orientation, , metadata: they're parameters, didn't retain it, must not release it
  • mutablemetadata: returned create, hence retained, must release it
  • mykey: not retained, must not release it
  • myvalue: returned create, it's retained, release
  • url: it's bridged directly (not bridge-retained or bridge-transfered), , method name doesn't have of retaining prefixes, it's not retained, must not release
  • destination: returned create, it's retained, release

see? it's pretty easy.


Comments