Importing VCard in objective C in iPhone - objective-c

I am developping an iPhone App using XCode 4.2 .in a portion of the App I will be getting a VCard as an NSString
I found this function initWithVCardRepresentation and i think it will be easier than parsing the data one by one (i.e getting the first name then the last name etc ... , but I have a hard time to implement it in my code .
I have the AddressBook and the AddressBookUI frameworks and I am trying to use this code but can t find an exact way to do it
-(IBAction)Add{
// I have a NSString *card defined somewhere else
ABAddressBookRef *iPhoneAddressBook = ABAddressBookCreate();
ABRecordRef *contact = ABPersonCreatePeopleInSourceWithVCardRepresentation(iPhoneAddressBook, (__bridge_retained CFStringRef) card);
CFRelease(contact);
CFRelease(iPhoneAddressBook);
}
when I compile ,it crashes at the line
ABRecordRef *contact = ABPersonCreatePeopleInSourceWithVCardRepresentation(iPhoneAddressBook, (__bridge_retained CFStringRef) card);
and I get the following green error in the #autoreleasepool
Thread1:Program Received Signal "SIGABRT".
I am quite new to the Apps development , please let me know if the information I gave is sufficient
Thanks

If you want to have an ABPerson afterwards (what is advisable), use:
// Assuming NSString *card exists already.
ABPerson *person = [[[ABPerson alloc] initWithVCardRepresentation:[card dataUsingEncoding:NSUTF8StringEncoding] autorelease];

Related

iTunes Mp3 Add Returning Nil Via Scripting Bridge In ObjC and Swift And Doesn't Import

I'm trying to import a downloaded MP3 into iTunes. My app is for OSX using Swift, and I've tried doing this both in Swift code and in ObjC using interoperability. I've generated the iTunes.h using sdef and sdp. I'm importing it in my Bridging Header for the Swift attempt and in my .m file for the ObjC attempt. I've added Scripting Bridge to my build.
This is my first program in Swift or ObjC (my experience is in C#) so this may be something simple I don't have the experience to realize.
Here is my ObjC code:
NSString *filepath = "~/Music/test.mp3";
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
iTunesPlaylist *pl;
for (iTunesSource *source in sources) {
if([source kind] == iTunesESrcLibrary) {
SBElementArray *libraries = [source libraryPlaylists];
pl = [libraries objectAtIndex:1];
break;
}
}
iTunesTrack *track = [iTunes add:[NSArray arrayWithObject:[NSURL fileURLWithPath:filepath]] to: pl];
Everything compiles and runs, but the iTunes add returns nil (and more importantly, doesn't add to iTunes). I've tried using different Playlists from the Library, and difference Sources as well. I've tried using a different MP3 file. And as I said, I've written it in Swift as well. All give me the same result.
So apparently I was fetching the path for MyMusic incorrectly. You can't just use the tilde, you have to resolve it:
NSString *musicDirectory = [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filepath = [musicDirectory stringByAppendingPathComponent:#"test.mp3"];
Or with Swift:
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.MusicDirectory, inDomains: .UserDomainMask)
let musicDirectory: NSURL = urls.first as? NSURL
let filepath = musicDirectory.URLByAppendingPathComponent("test.mp3")
At this point, I no longer needed to mess with any of the source searching either, I could just pass nil as the playlist:
iTunesTrack *track = [iTunes add:[NSArray arrayWithObject:[NSURL fileURLWithPath:filepath], nil] to: nil];
I still need an Objective C wrapper around the actual add method, however, which is connected to the Swift programming via the Bridging Header. If I try to use the add method in Swift directly, I get linker errors which seem unrelated to the original issue, so I won't address.

Can't save address to ABRecordRef

I'm trying to add an address to picked contact:
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
didSelectPerson:(ABRecordRef)person{
// Adding address
ABMutableMultiValueRef addressMultipleValue = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];
[addressDictionary setObject:#"8-15 Dereham Place" forKey:(NSString *)kABPersonAddressStreetKey];
[addressDictionary setObject:#"London" forKey:(NSString *)kABPersonAddressCityKey];
[addressDictionary setObject:#"EC2A 3HJ" forKey:(NSString *)kABPersonAddressZIPKey];
[addressDictionary setObject:#"United Kingdom" forKey:(NSString *)kABPersonAddressCountryKey];
[addressDictionary setObject:#"gb" forKey:(NSString *)kABPersonAddressCountryCodeKey];
ABMultiValueAddValueAndLabel(addressMultipleValue, (__bridge CFTypeRef)(addressDictionary), kABHomeLabel, NULL);
ABRecordSetValue(person, kABPersonAddressProperty, addressMultipleValue, nil);
CFErrorRef anError = NULL;
BOOL didSet;
didSet = ABAddressBookSave(_addressBook, NULL);
if (!didSet) {
NSError *er = (__bridge NSError *)(anError);
NSLog(#"Error saving record: %#", er.localizedDescription);}else{
NSLog(#"Record updated successfully");
}
CFRelease(addressMultipleValue);
}
As I see in console, there is no problem with saving it. However, when I open contact in Contacts App there is no saved address.
The release notes are REALLY helpful. Neither item referenced: "ABPeoplePickerNavigationController.h" or the new "PeoplePicker: Picking a Person or Property sample project" can be found.
Apple's "enhancement" has hosed 20 business apps of mine that rely on AB for contact info. Thanks again Apple for fixing something that wasn't broke.
Citing from iOS 8 Release Notes document:
The Address Book UI people picker has been changed for iOS 8. A new mode with new API has been added where the app does not need access to the user’s contacts and the user will not be prompted for access. A temporary copy of the selected person is returned to the app. See ABPeoplePickerNavigationController.h for more details.
See the new PeoplePicker: Picking a Person or Property sample project demonstrating usage of the new mode.
So you gonna meet the new API, until that, you're probably working just with temporary copies rather than actual database, that actually Contacts app accesses.

Sandboxing coreWLAN?

I'm writing an OS X application that depends on the ability to determine wireless signal strength, but I can't figure out what entitlements to use to sandbox it.
Whenever I use
NSMutableArray *scanResults;
CWInterface *currentInterface = [CWInterface interface];
NSLog(#"currInterface: %#\n", currentInterface);
NSMutableDictionary *signalsDict = [[NSMutableDictionary alloc] init];
NSError *err = nil;
scanResults = [NSMutableSet setWithSet:[currentInterface scanForNetworksWithSSID:nil error:&err]];
I get the error The operation couldn't be completed. (com.apple.coreWLAN.error error 1.) despite having all entitlements checked in XCode. What entitlement(s) am I missing?
The CoreWLANWirelessManager sample project has the same problem.
CoreWLAN doesn't seem to be available at all to sandboxed apps.
Apple's developer documentation states "With App Sandbox, your app cannot modify the system’s network configuration (whether with the System Configuration framework, the CoreWLAN framework, or other similar APIs)", which seems to imply that reading but not writing settings might be OK, but that doesn't seem to work in practice, and this is confirmed by a post by Apple DTS: https://forums.developer.apple.com/thread/11307
How about the entitlements for the Wifi Diagnostics app that ships with Mac OS X 10.11.1, located at /System/Library/CoreServices/Applications/. Checking entitlements I see that it posseses the following: com.apple.wifi.associate, com.apple.wifi.scan, com.apple.wifi.set_channel, com.apple.wifi.start_autojoin, com.apple.wireless-diagnostics, and com.apple.wireless-diagnostics.basic_report.
Are we mere mortals working in a sandbox not able to get these?
I think you need to check Outgoing Connections (Client).
You might want to use Apple80211 private framework by using dlfcn.h library. An iphone example can be found here:
http://www.csse.uwa.edu.au/~chris/iphone/APlogger/
Download the source file and investigate scanner module.
In summary, you will come up with something like this:
#define IF_NAME "en0"
#include <dlfcn.h>
- (void)performScan
{
int (*open)(void *);
int (*bind)(void *, NSString *);
int (*close)(void *);
int (*scan)(void *, NSArray **, void *);
void *libHandle;
void *airportHandle;
libHandle = dlopen("/System/Library/Frameworks/Preferences.framework/Preferences", RTLD_LAZY);
open = dlsym(libHandle, "Apple80211Open");
bind = dlsym(libHandle, "Apple80211BindToInterface");
scan = dlsym(libHandle, "Apple80211Scan");
close = dlsym(libHandle, "Apple80211Close");
open(&airportHandle);
bind(airportHandle, #IF_NAME);
NSArray *found;
NSDictionary *params = [[NSDictionary alloc] init];
scan(airportHandle, &found, params);
int nnw = [found count];
for(int i=0 ; i < nnw ; i++) {
NSDictionary *nw = [found objectAtIndex:i];
NSString *ssid = [self fixSSID:nw];
// RSSI indicates signal strength
int rssi = [[nw objectForKey:#"RSSI"] intValue];
}
// Cleanup
close(airportHandle);
dlclose(libHandle);
}
-(NSString *)fixSSID:(NSDictionary *)nw
{
if ([[nw objectForKey:#"HIDDEN_NETWORK"] boolValue])
return #"<hidden>";
else
return [nw objectForKey:#"SSID_STR"];
}
Note that if you use private frameworks in your iOS apps, you will not be able to publish them on App Store (Apple will reject your app because there is no public documentation for Apple80211 framework). but since your question is regarding OSX development, this doesn't apply for your case.
Hope it helps.

EXC_BAD_ACCESS on NSString sizeWithFont

I am not sure what is going on anymore. I have tried so many things to for me to figure out whats going on on this specific line of code that is causing a EXC_BAD_ACCESS.
I tried enabled NSZombies but it didn't help me any. Here is the code:
- (int)linesFromText:(NSString *)string withFont:(UIFont *)font andSize:(CGSize)size {
NSArray *splitString = [string componentsSeparatedByString:#" "];
NSMutableArray *allLines = [NSMutableArray array];
NSMutableString *line = [NSMutableString string];
NSString *word;
NSString *fakeLine;
for (int i = 0; i < splitString.count; i++) {
word = [splitString objectAtIndex:i];
fakeLine = [NSString stringWithFormat:#"%#%# ",line, word];
//NSLog(#"line %#, font %#",fakeLine,font);
////THIS IS THE LINE CAUSING THE EXC_BAD_ACCESS
CGSize lineSize = [fakeLine sizeWithFont:font];
if (lineSize.width <= size.width) {
[line appendFormat:#"%# ", word];
} else {
[allLines addObject:[line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
line = [NSMutableString string];
[line appendFormat:#"%# ", word];
}
}
[allLines addObject:[line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
return allLines.count;
}
This is driving me crazy cause it only happens on the new iphone 5 when you scroll through the days to fast in the app I built. Here is a link to the application in the store:
http://itunes.apple.com/us/app/id543324451?mt=8
if you have an iphone 5 you can see what I mean. iphone 4 doesn't do this.
This code is being called in a UITableViewCell's layoutSubviews and is there to help size the frame of a Custom Attributed label that uses TTTAttributedLabel (https://github.com/mattt/TTTAttributedLabel).
I also tried to enable "Gaurd malloc to try give me more details but my XCode gives me this error:
dyld: could not load inserted library '/usr/lib/libgmalloc.dylib' because image not found
which if I look in /usr/lib that file is a sym link to a file that does exist in the same directory:
libgmalloc.dylib -> libgmalloc.B.dylib
I am running out of ideas here and thought it might be the UIFont getting released to soon and then it not being available so I put references in the UITableViewCell to hold the UIFont until the end of that Cell's life.
I have also searched around the internet and haven't found that much on this specifics.
Also here is an image of my stack trace from debugger:
http://i.stack.imgur.com/gWC5L.png
Any ideas?
Did I provide enough info?
Thanks
I think your question is answered here:
UIStringDrawing methods don't seem to be thread safe in iOS 6
The short version: sizeWithFont, and most other UIKit methods, are not thread safe when you're using it on the screen (rather than using it to pre-render).
The good news: look at Adam Swinden's answer in that thread; he explains how to get the same result in iOS6 with CoreText instead of UIKit.

How can text files be written using Objective-C?

In .NET, a file can be written to the file system using:
FileStream fs = File.Create(#"Filename");
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("Hello, World!");
// etc...
sw.Close();
fs.Close();
How would I achieve the same operation in Objective-C and Cocoa? I believe it involves the NSMutableData class, but I do not know how to implement it.
Tiny Mac Tutorials has a post on this.
The example code from that post is below:
// filetest.m
// Created by macateeny.blogspot.com Sept 2008.
// Copyleft (c) 2008. some rights reserved.
//
// Compile from the command line with:
// gcc filetest.m -Wall -o filetest -framework Foundation
//
#import <Foundation/Foundation.h>
// main entry point of our file test tool with the argument counter and vector
int main(int argc,char *argv[])
{
// allocate a memory pool for our NSString Objects
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// declare NSString Obj pointer and initialise it
NSString *str = #"Cooking with Objective-C\r\n";
// declare NSString filename and alloc string value
NSString *filenameStr = #"./filetest.txt";
// NSObject which contains all the error information
NSError *error;
// write contents and check went ok
if(![str writeToFile: filenameStr atomically: YES encoding:NSUTF8StringEncoding error:&error]) {
NSLog(#"We have a problem %#\r\n",[error localizedFailureReason]);
}
// unleash the allocated pool smithers
[pool release];
// The app is terminated
return 0;
}
Note that Objective C is a pure superset of standard C . Most of the usual posix library calls (in stdio, stdlib, etc.) are available and usable, as long as you don't try to use them to escape the app's sandbox (write to system directories, etc.)
So fopen() and fprintf() will also work perfectly well for writing ASCII or UTF8 text and data to files. You can use NSSearchPathForDirectoriesInDomains to find the appropriate directory names, and use various NSString convenience methods to convert NSStrings to UTF8.
See Apple's development docs - Cocoa concepts especially for this re Strings The Apple overview documents of the librairead all the concepts first it will give you a idea of what details you need
For the latest version of Cocoa on iOS or MacOS you can do this if you don't want to check for an error,
NSString *str = #"Wollah";
[str writeToFile:#"Wollah.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
NSString *str = #"Wollah";
[str writeToFile:#"/Wollah.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
Although using an NSURL is recommended, and I always do that.
NSString has a writeToFile method.