Swift : Issue with accessing CFDictionaryRef for ABAddressBookRef - ios

I'v collected contact's address information in ObjC as,
ABMultiValueRef addressProperty = ABRecordCopyValue(contactRef, kABPersonAddressProperty);
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(addressProperty, 0);
if(dict)
{
NSString *street = (NSString *)CFDictionaryGetValue(dict, kABPersonAddressStreetKey);
}
So, equivalent Swift code would be,
let addressProperty : ABMultiValueRef = ABRecordCopyValue(contactRef, kABPersonAddressProperty).takeUnretainedValue() as ABMultiValueRef
if let dict : CFDictionaryRef = ABMultiValueCopyValueAtIndex(addressProperty, 0).takeUnretainedValue() as? CFDictionaryRef
{
let street = CFDictionaryGetValue(dict,kABPersonAddressStreetKey)
// Stuck here, among CFString!, UnsafePointer<Void>, CFDictionaryRef ...
}
How will I fetch street and other similar information?

Can you use NSDictionary instead? (not tested)
if let dict : NSDictionary = ABMultiValueCopyValueAtIndex(addressProperty, 0).takeUnretainedValue() as? NSDictionary
{
let street = dict[kABPersonAddressStreetKey]
}

Related

How to get a value from dictionary which is inside an array?

I want to store a message - "hi this is John KL", in some string, how to parse following example.
[
{
"message": "hi this is John KL"
}
]
Swift:
guard let anArray = input as? [[String:String]],
let message = anArray.first["message"] else {
print("unable to fetch data"
}
Objective-C:
- (void) readJSON {
NSError *result;
NSURL *url = [[NSBundle mainBundle] URLForResource: #"sample"
withExtension: #"JSON"];
NSData *data = [NSData dataWithContentsOfURL: url
options: 0
error: &result];
if (result != nil) {
NSLog(#"Error reading file: %#", result);
return;
}
NSArray<NSDictionary<NSString*, NSString*> *> *array = [NSJSONSerialization JSONObjectWithData: data options: 0 error: &result];
if (result != nil) {
NSLog(#"Error converting JSON: %#", result);
return;
}
else {
NSLog(#"\nJSON data = \n%#", array);
if (array.count < 1) {
NSLog(#"Not enough elements in array");
return;
}
NSString *message = array[0][#"message"];
if (message == nil) {
NSLog(#"Unable to fetch message");
} else {
NSLog(#"Message = \"%#\"", message);
}
}
}
The above Objective-C code does not test to make sure the object read from the JSON file is the correct type. It will crash if it is not an array containing a dictionary with a string key and string value. For a production app you'll want to add code to type-check the data.
Swift
Assign your json array to a variable type of [String : String] or [String : Any] dictionary array. [String : Any] is most commonly used dictionary but according to your data it suites with [String : String]
if let array = [
{
“message” : “hi this is John KL”
}
] as [Any]
Now, get your json/dictionary from array using index value and then get string from json using json key.
if let dictionary = array.first as? [String : Any] {
if let stringMessage = dictionary["message"] as? String {
print("stringMessage - \(stringMessage)")
}
}
Objective-C
NSArray * array = [
{
“message” : “hi this is John KL”
}
];
NSDictionary * dictionary = (NSDictionary *)[array objectAtIndex: 0];
NSString * stringMessage = (NSString *)[dictionary valueForKey: "message"];
NSLog(#"stringMessage - %#",stringMessage);
You can try this answer.
NSArray *result = [json objectForKey:#"result"];
for(NSString *currenObject in result){
NSLog(#"%#",currenObject);
NSString *currentValue = [currenObject valueForKey:#"message"];
}
NSLog(#"%#",currentValue);

convert from CGImageMetadata to nsdictionary

i tried to convert my 360° metadata image to nsdictionary. every time the app crash when i tried to print a value for an attribute. i wrote this code
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
NSArray *metadataArray = nil;
if (source) {
_metaData = CGImageSourceCopyMetadataAtIndex(source, 0, NULL);
if (_metaData) {
metadataArray = CFBridgingRelease(CGImageMetadataCopyTags(_metaData));
CFRelease(_metaData);
}
CFRelease(source);
}
NSLog(#"%#",metadataArray[12]);//this is the problem
In the output, i find that the type of immutableMetadata is CGImageMetadata not a NSdictionary. How i can convert to nsdictionary please??
Swift
extension CGImageSource {
func metadata() -> Dictionary<String, Any>? {
guard let imageMetadata = CGImageSourceCopyMetadataAtIndex(self, 0, .none) else {
return .none
}
guard let tags = CGImageMetadataCopyTags(imageMetadata) else {
return .none
}
var result = [String: Any]()
for tag in tags as NSArray {
let tagMetadata = tag as! CGImageMetadataTag
if let cfName = CGImageMetadataTagCopyName(tagMetadata) {
let name = String(cfName)
let value = CGImageMetadataTagCopyValue(tagMetadata)
result[name] = value
}
}
return result
}
}
I don't know much about ImageIO. It's full of CF/CG stuff, which may lead to __bridge uses.
You are only interested in a value, but if someone is looking for another, it could use that sample code/research:
I looked into CGImageMetadata.h for each use of functions related to CGImageMetadataTagRef that may be useful.
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imagedata, NULL);
CGImageMetadataRef imageMetadataRef = CGImageSourceCopyMetadataAtIndex(source, 0, NULL);
NSArray *metadata = CFBridgingRelease(CGImageMetadataCopyTags(imageMetadataRef));
NSLog(#"metadata = %#", metadata);
for (id aRef in metadata)
{
CGImageMetadataTagRef currentRef = (__bridge CGImageMetadataTagRef)(aRef);
NSLog(#"Ref: %#", currentRef);
CGImageMetadataType type = CGImageMetadataTagGetType(currentRef);
NSLog(#"Type: %d", type);
CFStringRef nameSpace = CGImageMetadataTagCopyNamespace(currentRef);
NSLog(#"NameSpace: %#", nameSpace);
CFStringRef prefix = CGImageMetadataTagCopyPrefix(currentRef);
NSLog(#"prefix: %#", prefix);
CFStringRef name = CGImageMetadataTagCopyName(currentRef);
NSLog(#"name: %#", name);
CFTypeRef value = CGImageMetadataTagCopyValue(currentRef);
NSLog(#"Value: %#", value);
CFStringRef valueTypeStr = CFCopyTypeIDDescription(CFGetTypeID(value));
NSLog(#"valueTypeStr: %#", valueTypeStr);
//Test related to question
if ([#"GPano" isEqualToString:(__bridge NSString *)prefix] && [#"PoseHeadingDegrees" isEqualToString:(__bridge NSString *)name])
{
NSString *str = (__bridge NSString *)value;
NSLog(#"Str: %#", str);
NSLog(#"Int: %d", [str intValue]);
}
}
To know if the value is convertible to a more "known" object, like NSString (<=> CFString), NSArray (<=> CFArray), NSDictionary (<=> CFDictionary), I looked at CFStringRef valueTypeStr = CFCopyTypeIDDescription(CFGetTypeID(value)); (or you can also do a "quicker test" with related question: Determining what a CFTypeRef is?).
It's all "manually" done, I'm quite surprised that there is no conversion from CGImageMetadataTagRef to a more "known" object (and not struct), maybe there is, I didn't read the whole headers of CGImageMetadata.h, so there may be a quicker way, but I thought that even using "old school" approach, by digging could be useful for another user with a related question, helping him/her to find quickly what's he/she is looking for.
To answer your initial question: CGImageMetadata to NSDictionary, if there is no "easy conversion" tool, and with the "digging" approach, it's won't make a lot of sense, because the interesting method CGImageMetadataCopyTags returns a NSArray (or CFArray).
But since a lot of CGImageMetadataTagRef prefix are the same, you may be interested, by doing manually the following dictionary:
#{prefix1:#[stuff10, stuff11, etc.], prefix2:#[stuff20, stuff21, etc.]}

ios/c/addressbook: Parse kABPersonAddressProperty crash

I am using the following code to retrieve different address fields from the Addressbook. It works okay for name and some properties but crashes with address. I suspect that the address is an int rather than string but can't find anything in the docs to explain why it should be different. Would appreciate any suggestions:
//This works:
CFStringRef jobtitleRef = nil;
jobtitleRef = ABRecordCopyValue(addressBookRecord, kABPersonJobTitleProperty);
NSString *jobtitle = #"";
if (jobtitleRef!=nil) {
jobtitle =[jobtitle stringByAppendingString:(__bridge NSString *)jobtitleRef];
}
//But this crashes
CFStringRef addr1Ref = nil;
addr1Ref = ABRecordCopyValue(addressBookRecord, kABPersonAddressProperty);
NSString *addr1 = #"";
if (addr1Ref!=nil) {
addr1 = [addr1 stringByAppendingString:(__bridge NSString *)addr1Ref]; //crashes on this line
}
Edit:
Found the answer in another question:
ABMultiValueRef st = ABRecordCopyValue(person, kABPersonAddressProperty);
if (ABMultiValueGetCount(st) > 0) {
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(st, 0);
self.street.text = CFDictionaryGetValue(dict, kABPersonAddressStreetKey);
}

Accessing the xml values from NSDictionary

I am using this xmlreader. Here is my code
NSDictionary *xmlDict = [XMLReader dictionaryForXMLString:responseString error:&error1];
NSLog(#"XMLData: %#",xmlDict);
I can save and log the data and it looks like this.
response = {
Gpn0 = {
text = 10000;
};
Gsn0 = {
text = 4;
};
btn0 = {
text = up;
};
};
}
But how can I access a single element from this dictionary?
NSDictionary *gpn0 = response[#"Gpn0"];
NSNumber *gpn0_text = gpno[#"text"]; // note this is a numeric value
NSDictionary *btn0 = response[#"btn0"];
NSString *btn0_text = gpno[#"text"]; // note this is a string value
so on and so forth

Avmetadataitem Getting the trackNumber from an iTunes or ID3 metadata on iOS

I'm trying to get the trackNumber of a aac, mp3 or mp4 file. It's not in the commonMetadata so I started to spelunk in the other metadata keys. I found something that looks like it, but I'm yet unable to read it, and make sense of it. Even the raw data makes no sense to me.
At the moment, I'm just trying to get it using this basic code:
NSArray *meta = [asset metadataForFormat:AVMetadataFormatiTunesMetadata];
for ( AVMetadataItem* item in meta ) {
id key = [item key];
NSString *value = [item stringValue];
NSLog(#"key = %#, value = %#", key, value);
}
Knowing I'm looking for AVMetadataiTunesMetadataKeyTrackNumber.
I realize this thread is quite old but I recently came across this issue myself. I needed ALL the metadata I could gather and came up with the following solution. It's not the most elegant solution but it works well enough. Written in Swift.
func processFile(url:NSURL) {
let yearKey = -1453039239
let genreKey = -1452841618
let encoderKey = -1451987089
let trackKey = "com.apple.iTunes.iTunes_CDDB_TrackNumber"
let CDDBKey = "com.apple.iTunes.iTunes_CDDB_1"
let path:String = url.absoluteString
let asset = AVURLAsset(URL: url, options: nil)
let format = AVMetadataFormatiTunesMetadata
for item:AVMetadataItem in asset.metadataForFormat(format) as Array<AVMetadataItem> {
if let key = item.commonKey { if key == "title" { println(item.value()) } }
if let key = item.commonKey { if key == "artist" { println(item.value()) } }
if let key = item.commonKey { if key == "albumName" { println(item.value()) } }
if let key = item.commonKey { if key == "creationDate" { println(item.value()) } }
if let key = item.commonKey { if key == "artwork" { println( "art" ) } }
if item.key().isKindOfClass(NSNumber) {
if item.key() as NSNumber == yearKey { println("year: \(item.numberValue)") }
if item.key() as NSNumber == genreKey { println("genre: \(item.stringValue)") }
if item.key() as NSNumber == encoderKey { println("encoder: \(item.stringValue)") }
}
if item.key().isKindOfClass(NSString) {
if item.key() as String == trackKey { println("track: \(item.stringValue)") }
if item.key() as String == CDDBKey { println("CDDB: \(item.stringValue)") }
}
}
}
If your track has ID3 metadata, you can easily get the numberValue for the track number. If your track has iTunesMetadata, the dataValue is all you get. You have to guess the intValue yourself.
So far, I'm here. I'm pretty sure I need to work more on the bytes portion.
NSArray *meta = [asset metadataForFormat:AVMetadataFormatiTunesMetadata];
NSArray *itfilteredKeys = [AVMetadataItem metadataItemsFromArray:meta withKey:AVMetadataiTunesMetadataKeyTrackNumber keySpace:nil];
for ( AVMetadataItem* item in itfilteredKeys ) {
NSData *value = [item dataValue];
unsigned char aBuffer[4];
[value getBytes:aBuffer length:4];
unsigned char *n = [value bytes];
int value1 = aBuffer[3];
NSLog(#"trackNumber from iTunes = %i", value1);
}
This question is rather old, but I came upon it as I had a similar problem, so for anyone who still needs a solution. I managed to figure out a way of getting the total tracks number and the track number using the following code:
NSString *value = #"<0000000a 00140000>" //[item stringValue] (in this case 10/20)
NSString *track_no_hex = [[value componentsSeparatedByString:#" "][0] stringByReplacingOccurrencesOfString:#"<" withString:#""];
NSString *total_track_no_hex = [[value componentsSeparatedByString:#" "][1] stringByReplacingOccurrencesOfString:#">" withString:#""];
NSString *track_no = #"";
for(int k=0;k<=4;k+=4){
unsigned result = 0;
NSScanner *scanner = [NSScanner scannerWithString:[track_no_hex substringWithRange:NSMakeRange(k, 4)]];
[scanner scanHexInt:&result];
if(result == 00){
}
else{
track_no = [NSString stringWithFormat:#"%#%u",track_no,result];
}
}
NSString *total_track_no = #"";
for(int k=0;k<=4;k+=4){
unsigned result = 0;
NSScanner *scanner;
if(k+4<=[total_track_no_hex length]){
scanner = [NSScanner scannerWithString:[total_track_no_hex substringWithRange:NSMakeRange(k, 4)]];
}
else{
}
[scanner scanHexInt:&result];
if(result == 00){
}
else{
total_track_no = [NSString stringWithFormat:#"%#%u",total_track_no,result];
}
}
NSLog(#"%#/%#",track_no, total_track_no); // Output 10/20
This will work fine for track numbers under 14461 which should be large enough considering iTunes max track number is 999.

Resources