I use ABUnknownPersonViewController to display a contact view.
I try to set an image with:
NSData *dataRef = UIImagePNGRepresentation([UIImage imageNamed:#"contact3.png"]);
ABPersonSetImageData(newPersonViewController.displayedPerson, (CFDataRef)dataRef, nil);
It doesn't work and I don't know why. Any ideas?
You can't just cast an NSData object to a CFDataRef; as noted in the docs, a CFDataRef is a "reference to an immutable CFData object", which is not the same as an NSData instance:
typedef const struct __CFData *CFDataRef;
To create the CFDataRef from the NSData instance, you need to use the CFDataCreate method, passing the bytes and length:
NSData *dataRef = UIImagePNGRepresentation([UIImage imageNamed:#"contact3.png"]);
CFDataRef dr = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);
Note also that since you create the object yourself, you must also release it, following the Core Foundation Ownership Policy; you use the CFRelease function to release ownership of the Core Foundation object:
CFRelease(dr);
This is similar to the Memory Management in Cocoa, and once the retain count of the Core Foundation object reaches zero it will be deallocated.
Edit: Stefan was completely right, in his comment, that NSData and CFData are also toll-free bridged on the iPhone with Cocoa-Touch as with Cocoa, so my original answer was wrong. My fault, should have edited it before.
Related
I have a method which is returning NSMutableData. I need to pass this NSMutableData to another method but that method is expecting only NSData. I am trying to find any method/solution to convert NSMutableData to NSdata. But still no luck.
In Objective C, it can be done like this
NSData *immutableData = [NSData dataWithData:mutableData];
I am not sure how it can be done in Swift?Can someone help me in this?
Simply pass the NSMutableData to any method that expects NSData. Since it's a subclass, it will work fine.
But if you really want to do the conversion, simply do (Swift 3):
let data = someNSMutableDataVariable.copy() as! NSData
or
let data = NSData(data: someNSMutableDataVariable as Data)
It may make sense to update your code to use Data instead of NSMutableData or NSData. Just like using String instead of NSString and NSMutableString.
I have a huge NSMutableData object(approximately 1 MB in size) in memory and now I want to replace all the bytes in the object to 0 (not deallocate the memory). The resetBytesInRange method lets me do this. However how do I verify/check if the bytes are actually set to 0. I want to look at the memory addresses and confirm this. Is this possible?
I have the following code
NSMutableData *imgData = [NSMutableData dataWithCapacity:50000000];
imgData = (NSMutableData*)UIImageJPEGRepresentation(img, 1.0);
[imgData resetBytesInRange:NSMakeRange(0, [imgData length]) ];
Now when I look into the address pointed to by imgData (and the following few locations), before and after the resetBytes, I do not see any change in the values in the memory locations starting from the address pointd to by imgData (I expected to see zeros assigned). I assumed that the memory allocations are contiguous starting from the the address pointed to by imgData (upto [imgData length]). Is this assumption corerct (which seems like it is not)? If not where are the bytes in the NSMutableData object stored? Can I access them individually?
Thanks
Vivek
The problem is not that -resetBytesInRange: doesn't work. The problem is that you're sending that message to the wrong object.
imgData = (NSMutableData*)UIImageJPEGRepresentation(img, 1.0); doesn't assign the JPEG bytes to the mutable data you created in the first line. It replaces your reference to that object with a reference to a new object, and uses a cast to suppress the compiler warning about an invalid store. There are a few ways to do this properly:
NSMutableData *imgData = [NSMutableData data]; /* note, we do not specify a capacity--it's pointless for this use case */
[imgData setData: UIImageJPEGRepresentation(img, 1.0)];
[imgData resetBytesInRange: NSMakeRange(0, [imgData length])];
Or:
NSMutableData *imgData = [[UIImageJPEGRepresentation(img, 1.0) mutableCopy] autorelease];
[imgData resetBytesInRange: NSMakeRange(0, [imgData length])];
But both ignore the obvious: if you're immediately clearing the data to zero, why are you even bothering to create the JPEG data? What are you actually trying to do here?
imgData is a pointer (as indicated by the * symbol). So it points to a memory location and assignment will just change the location it points to. It's not really the intention of most programming languages to let you do byte-by-byte manipulation of actual memory locations.
Read this: http://www.cplusplus.com/forum/general/3644/
I have been using NSJSONSerialization class for converting fields of my object to JSON. Sadly only NSString, NSNumber, NSArray, NSDictionary, or NSNull types are supported.
As my object has one additional field, that is UIImage, I am at loss as to how to deal with it. I am sure many people have encountered this common problem, so what is best method to approach this?
You can encode UIImage data by base64, and add it to json object.
To get data from UIImage, you can use UIImagePNGRepresentation and UIImageJPEGRepresentation.
The code like this,
NSData *imageData = UIImagePNGRepresentation(image);
NSString *base64encodedStr = base64encode(imageData);
[dict setObject:base64encodedStr forKey:#"myImage"];
//then covert dict to json object.
To restore UIImage data, just parse json object and decode the data by base64.
Hope this can help you.
You could convert your images data to a string and then write that string.
NSData *imageData = UIPNGRepresentation(image);
NSString *imageString = [[NSString alloc] initWithData:imageData encoding:NSUTF8StringEncoding];
//I don't know how to use NSJSONSerialization
//[NSJSONSerialization serializeString:imageString];
NSString *base64encodedStr = [imageData base64Encoding];
I am having trouble converting a CFDataRef into NSData whilst using ARC. I am using the __bridge_transfer OR __bridge cast but it is not working. Could anyone suggest me some other way of casting this two types.
I get the following error
Automatic Reference Counting Issue: Incompatible types casting 'CFDataRef *' (aka 'const struct __CFData **') to 'NSData *' with a __bridge cast
NSData *my_nsdata = (__bridge_transfer NSData*)my_cfdata; // -1 on the my_cfdata
or
NSData *my_nsdata = (__bridge NSData*)my_cfdata; // no adjustment of retain counts.
From my blog post here:
http://amattn.com/2011/12/07/arc_best_practices.html
How do I convert a UIImage to NSData or CFDataRef? I need to pass a CFDataRef to ABPersonSetImageData.
This worked for me, for a PNG image. For other image types, I assume you just have to find the corresponding UIImage...Representation method.
UIImage *image = [UIImage imageNamed:#"imageName.png"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
If you need a CFDataRef for a UIImage, it's just one more line.
CFDataRef imgDataRef = (CFDataRef)imageData;
you can use this
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
and simply cast imageData to CFDataRef
CFDataRef = (CFDataRef) imageData;
CFDataRef cfdata = CFDataCreate(NULL, [imageData bytes], [imageData length]);
For a working example click here.
Thank you.
For those who wondering what is difference between NSData and CFData, here is the explanation from Apple Docs:
CFData is “toll-free bridged” with its Cocoa Foundation counterpart,
NSData. What this means is that the Core Foundation type is
interchangeable in function or method calls with the bridged
Foundation object. In other words, in a method where you see an NSData
* parameter, you can pass in a CFDataRef, and in a function where you see a CFDataRef parameter, you can pass in an NSData instance. This
also applies to concrete subclasses of NSData. See Toll-Free Bridged
Types for more information on toll-free bridging.
This explains why casting NSData to CFData works.