Exporting all contacts in one .vcf file using Contacts.Framework in Objective - C - objective-c

Using I AddressBook.framework I used to create Contacts.vcf from all contacts and save it in Documents Directory.
Here is the code I used to use :
ABAddressBookRef addressBook1 = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook1);
long cnt = (unsigned long)[arrayOfAllPeople count];
if (cnt==0) {
ABAddressBookRequestAccessWithCompletion(addressBook1, nil);
}
if(ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
ABAddressBookRef addressBook2 = ABAddressBookCreate();
CFArrayRef contacts = ABAddressBookCopyArrayOfAllPeople(addressBook2);
CFDataRef vcards = (CFDataRef)ABPersonCreateVCardRepresentationWithPeople(contacts);
NSString *vcardString = [[NSString alloc] initWithData:(__bridge NSData *)vcards encoding:NSUTF8StringEncoding];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folderPath = [paths objectAtIndex:0];
NSString *filePath = [folderPath stringByAppendingPathComponent:#"Contacts.vcf"];
[vcardString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
CFRelease(addressBook2); }
How do I create a Contacts.vcf file having all device contacts using Contacts.framework and save it in documents directory ?

You can use this method to get all the contacts in .vcf file. It return the same output that you get using AddressBook.framework.
- (void)getContacts {
NSMutableArray *contactsArray=[[NSMutableArray alloc] init];
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!granted) {
dispatch_async(dispatch_get_main_queue(), ^{
});
return;
}
NSMutableArray *contacts = [NSMutableArray array];
NSError *fetchError;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:#[[CNContactVCardSerialization descriptorForRequiredKeys], [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]];
BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) {
[contacts addObject:contact];
}];
if (!success) {
NSLog(#"error = %#", fetchError);
}
// you can now do something with the list of contacts, for example, to show the names
CNContactFormatter *formatter = [[CNContactFormatter alloc] init];
for (CNContact *contact in contacts) {
[contactsArray addObject:contact];
// NSString *string = [formatter stringFromContact:contact];
//NSLog(#"contact = %#", string);
}
//NSError *error;
NSData *vcardString =[CNContactVCardSerialization dataWithContacts:contactsArray error:&error];
NSString* vcardStr = [[NSString alloc] initWithData:vcardString encoding:NSUTF8StringEncoding];
NSLog(#"vcardStr = %#",vcardStr);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folderPath = [paths objectAtIndex:0];
NSString *filePath = [folderPath stringByAppendingPathComponent:#"Contacts.vcf"];
[vcardStr writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}];
}

From iOS 9+ version AddressBookUI.framework and Addressbook.framework becomes deprecated. Apple introduced ContactUI.framework and Contact.framework with enhancements over AddressBookUI.framework and Addressbook.framework. In this blog we will talk about how to use these two new frameworks and export VCard. Let’s start picking contact from phone contacts and access basic information of that person.
Step 1. Create new Xcode project name ContactDemo and import Contacts.framework and ContactsUI.framework as shown in picture.
Step 2. In project add UIButton, UIImageView and 3 UILabels as shown in picture :
Step 3. Create outlets of button action, imageview and labels in respective view controller as :
#property (weak, nonatomic) IBOutlet UIImageView *personImage;
#property (weak, nonatomic) IBOutlet UILabel *personName;
#property (weak, nonatomic) IBOutlet UILabel *emailId;
#property (weak, nonatomic) IBOutlet UILabel *phoneNo;
- (IBAction)selectAction:(id)sender;
Step 4. Add delegate CNContactPickerDelegate to viewController.
Step 5. Add delegate method :
- (void) contactPicker:(CNContactPickerViewController *)picker
didSelectContact:(CNContact *)contact {
[self getContactDetails:contact];
}
This delegate method will return contact in the form of CNContact object which will be further processed in local method
-(void)getContactDetails:(CNContact *)contactObject {
NSLog(#"NAME PREFIX :: %#",contactObject.namePrefix);
NSLog(#"NAME SUFFIX :: %#",contactObject.nameSuffix);
NSLog(#"FAMILY NAME :: %#",contactObject.familyName);
NSLog(#"GIVEN NAME :: %#",contactObject.givenName);
NSLog(#"MIDDLE NAME :: %#",contactObject.middleName);
NSString * fullName = [NSString stringWithFormat:#"%# %#",contactObject.givenName,contactObject.familyName];
[self.personName setText:fullName];
if(contactObject.imageData) {
NSData * imageData = (NSData *)contactObject.imageData;
UIImage * contactImage = [[UIImage alloc] initWithData:imageData];
[self.personImage setImage:contactImage];
}
NSString * phone = #"";
NSString * userPHONE_NO = #"";
for(CNLabeledValue * phonelabel in contactObject.phoneNumbers) {
CNPhoneNumber * phoneNo = phonelabel.value;
phone = [phoneNo stringValue];
if (phone) {
userPHONE_NO = phone;
}}
NSString * email = #"";
NSString * userEMAIL_ID = #"";
for(CNLabeledValue * emaillabel in contactObject.emailAddresses) {
email = emaillabel.value;
if (email) {
userEMAIL_ID = email;
}}
NSLog(#"PHONE NO :: %#",userPHONE_NO);
NSLog(#"EMAIL ID :: %#",userEMAIL_ID);
[self.emailId setText:userEMAIL_ID];
[self.phoneNo setText:userPHONE_NO];
}
Step 6. Create CNContactPickerViewController class object and register its delegate in button IBAction method :
- (IBAction) selectAction:(id)sender {
CNContactPickerViewController *contactPicker = [CNContactPickerViewController new];
contactPicker.delegate = self;
[self presentViewController:contactPicker animated:YES completion:nil];
}
[self presentViewController:contactPicker animated:YES completion:nil]; will present view of contact list.
Step 7. Run project
A . Main View
B. On Tapping “Select Contact” button CNContactPickerViewController will open as shown in picture :
C. Pick one contact and view will dismiss and you will get details of that contact as shown in picture :
Earlier we have write permission code to access contacts but now it implicitly grants permission for accessing contacts. With this framework we can also generate VCard(VCF) and share among other platforms. Here is the steps to create VCard.
Step 1. Pick contact from CNContactPickerViewController and you will get CNContact Object in delegate as mention above.
Step 2. Save contact in document directory. As data is stored in NSData form so to convert contact to NSData
use CNContactVCardSerialization class that represents VCard in NSData format.
- (NSString *) saveContactToDocumentDirectory:(CNContact *)contact {
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString * VCardPath = [documentsDirectory stringByAppendingString:#"/VCard.vcf"];
NSArray *array = [[NSArray alloc] initWithObjects:contact, nil];
NSError *error;
NSData *data = [CNContactVCardSerialization dataWithContacts:array error:&error];
[data writeToFile:VCardPath atomically:YES];
return VCardPath;
}
CNContactVCardSerialization class method dataWithContacts:error: takes array of contact objects(CNContact class Object).
saveContactToDocumentDirectory method will return the file path of Vcard. With File path you can export contact anywhere you want.
Source: Contacts UI, Contacts Framework and create VCard(VCF) in Objective-C

Related

How to add multiple email attachments using UIActivityItemProvider

I'm working on an iOS app in which I want to add MULTIPLE attachments to an email using UIActivityItemProvider. I want to do it using UIActivityItemProvider because I do not want to incur the overhead of processing the record before I display the UIActivtyViewController to the user. If I pass in one image using an NSData or an NSURL object to the "url" element of the returned object, then the inline image shows fine. If I pass in an array of these objects then nothing shows up. I believe that passing an array will work if I use the ActivityItems parameter when initializing an NSActivityViewController, but again, I do not want to do this because I want to take advantage of the delayed processing available by using the UIActivityItemProvider. Below is my code
#implementation NoteRecordActivityProvider
- (id)initWithPlaceholderItem:(id)placeholderItem
{
//Initializes and returns a provider object with the specified placeholder data
return [super initWithPlaceholderItem:placeholderItem];
}
- (id)item
{
// //Generates and returns the actual data object
NSData *imageFile = [[NSData alloc]init];
NSString *imageFileName;
NSURL *url;
NSString* exportPath;
NSMutableArray* imageArray = [[NSMutableArray alloc]initWithCapacity:0];
NSInteger photoCount = self.noteRecord.photoCount;
for (NSInteger i = 0; i < photoCount; i+=1)
{
//Add File Attachment
PhotoObject *po = (PhotoObject*)[self.noteRecord photoObjects:i];
NSString *photoGUID = [(PhotoObject*)[self.noteRecord photoObjects:i]GUID];
imageFile = ImageDataReturningMethodHere;
imageFileName = [[NSArray arrayWithObjects:#"Image", [NSString stringWithFormat:#"%ld", (long)i], #".png", nil] componentsJoinedByString:#""];
exportPath = [[FileSystemProvider exportPath] stringByAppendingPathComponent:imageFileName];
[imageFile writeToFile:exportPath atomically:YES];
url = [NSURL fileURLWithPath:exportPath];
[imageArray addObject:url];
}
if ([self.activityType isEqualToString:UIActivityTypeMail])
return imageArray;
else
return nil;
}
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
return #{#"body":#"", #"url":[[NSURL alloc]init]};
}
-(NSString *) activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {
return [NSString stringWithFormat:#"Attached Record: %#", self.noteRecord.title];
}
#end
I did find the answer to this question. First I created an PhotoAttachmentActivityProvider that had a property for the source document which contains the photo I wanted to attach, and an index to the attachment in that document. I'm pasting my code here which uses a custom document called a NoteRecord:
#interface EMailPhotoAttachmentItemProvider : UIActivityItemProvider
#property (nonatomic, readwrite) NSInteger photoIndex;
#property (nonatomic, strong) NoteRecord* noteRecord;
#end
Then when I am showing the UIActivityViewController I add 1 of these custom UIActivityItemProvider objects for each attachment:
for (NSInteger i = 0; i < self.noteRecord.photoCount; i++)
{
EMailPhotoAttachmentItemProvider* photoProvider = [[EMailPhotoAttachmentItemProvider alloc]initWithPlaceholderItem:#{#"body":textToShare, #"url":url}];
photoProvider.photoIndex = i;
photoProvider.noteRecord = self.noteRecord;
[activityProviders addObject:photoProvider];
}
//Initialize the ActivityViewController
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityProviders applicationActivities:applicationActivities];
Then in the custom UIActivityItemProvider I check for whether I'm processing a EMAIL, and then I create a URL for the image using the document and image index provided:
#import "EMailPhotoAttachmentItemProvider.h"
#import "MiscUtilities.h"
#import "FileSystemProvider.h"
#implementation EMailPhotoAttachmentItemProvider
- (id)initWithPlaceholderItem:(id)placeholderItem
{
//Initializes and returns a provider object with the specified placeholder data
return [super initWithPlaceholderItem:placeholderItem];
}
- (id)item
{
if ([self.activityType isEqualToString:UIActivityTypeMail])
{
// Code here gets the image file from the NoteRecord at the PhotoIndex provided to
// the UIActivityItemProvider at the imageIndex, creates a URL for that image and returns it here.
// Your implementation will vary
PhotoObject *po = (PhotoObject*)[self.noteRecord photoObjects:self.photoIndex];
NSString *photoGUID = [(PhotoObject*)[self.noteRecord photoObjects:self.photoIndex]GUID];
NSData *imageFile = [[[MiscUtilities getApplicationDelegate]imageProvider]imageDataWithCaptionFromGUID:photoGUID caption:po.caption maxResolution:600];
NSString *imageFileName = [[NSArray arrayWithObjects:#"Image", [NSString stringWithFormat:#"%ld", (long)self.photoIndex], #".png", nil] componentsJoinedByString:#""];
imageFileName = [[FileSystemProvider exportPath] stringByAppendingPathComponent:imageFileName];
[imageFile writeToFile:imageFileName atomically:YES];
NSURL *url = [NSURL fileURLWithPath:imageFileName];
return url;
}
else
{
return nil;
};
}
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
NSString* defaultImagePath = [[FileSystemProvider imagePath]stringByAppendingPathComponent:#"default.png"];
NSURL *url = [[NSURL alloc]initWithString:defaultImagePath];
return #{#"body":#"", #"url":url};
}
#end

Xcode desktop directory and writeToFile: always with different name COCOA APPLICATION

I am creating a application that screenshot the mac desktop...
But I am having 2 problems:
what is the "global" directory of desktop?
In my computer is /Users/miguelcosta/Desktop/ but i want a directory that works for all macs..
My second problem is:
When you screenshot he creates a image on your desktop with the name Result.jpg. However when you take another screenshot he replace the previous screenshot... So I was thinking how can I save this images always with a different name...
Here is my code:
NSString *targetPath =#"/Users/miguelcosta/Desktop/Result.jpg";
NSData *imageData = [newImage TIFFRepresentation];
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
[imageData writeToFile:targetPath atomically:NO];
Thanks for your help!
Here is a code snippet... Refer also to this topic: Getting desktop path for current user on OS X
#import "ViewController.h"
#interface ViewController()
{
NSInteger _count;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_count = 1;
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES );
NSString* desktopPath = [paths objectAtIndex:0];
NSString *fileName = #"Result.jpg";
NSString *filePath = [NSString stringWithFormat:#"%#/%#", desktopPath, fileName];
filePath = [self filePathWithPath:filePath];
// write to file now using filePath ...
}
// generate new name ...
- (NSString*)filePathWithPath:(NSString*)filePath
{
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSArray *parts = [[filePath lastPathComponent] componentsSeparatedByString:#"."];
NSString *name = parts[0];
NSString *ext = parts[1];
filePath = [self filePathWithPath:[NSString stringWithFormat:#"%#/%#%ld.%#", filePath, name, _count++, ext]];
}
return filePath;
}
#end

Objective C assigning a dictionary to a variable and accessing it

I'm sorry to ask this question again, but I'm still stuck.
I have a city object trying to fetch weather from a weather fetcher object
#interface WeatherFetcher : NSObject {
}
#property (nonatomic, strong) NSMutableDictionary *weatherData;
- (void)fetchWeather:(NSString *)cityName;
- (void)handleNetworkErorr:(NSError *)error;
- (void)handleNetworkResponse:(NSData *)myData;
#end
This is were I assign the value to weatherData
#import "WeatherFetcher.h"
#implementation WeatherFetcher
- (void)fetchWeather:(NSString *)cityName
{
NSString *urlString = #"http://api.openweathermap.org/data/2.5/weather?q=";
urlString = [urlString stringByAppendingString:cityName];
urlString = [urlString stringByAppendingString:#",Aus"];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError)
{
[self handleNetworkErorr:connectionError];
}
else
{
[self handleNetworkResponse:data];
}
}];
}
#pragma mark - Private Failure Methods
- (void)handleNetworkErorr:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"Please try again later" delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
}
#pragma mark - Private Success Methods
- (void)handleNetworkResponse:(NSData *)myData
{
//NSMutableDictionary *data = [NSMutableDictionary dictionary];
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
// now we'll parse our data using NSJSONSerialization
id myJSON = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:nil];
// typecast an array and list its contents
NSDictionary *jsonArray = (NSDictionary *)myJSON;
//NSLog([jsonArray description]);
// take a look at all elements in the array
for (id element in jsonArray) {
id key = [element description];
id innerArr = [jsonArray objectForKey:key];
NSDictionary *inner = (NSDictionary *)innerArr;
if ([inner conformsToProtocol:#protocol(NSFastEnumeration)]) {
for(id ele in inner) {
if ([ele conformsToProtocol:#protocol(NSFastEnumeration)]) {
NSDictionary *innerInner = (NSDictionary *)ele;
for(id eleEle in innerInner) {
id innerInnerKey = [eleEle description];
[data setObject:[[inner valueForKey:innerInnerKey] description] forKey:[eleEle description]];
}
}
else {
id innerKey = [ele description];
[data setObject:[[inner valueForKey:innerKey] description] forKey:[ele description]];
}
}
}
else {
[data setObject:[inner description] forKey:[element description]];
}
}
self.weatherData = data;
NSLog([self.weatherData description]) **//there is data**
}
#end
However every time I call this from by city object I get nothing back at all.
#import <Foundation/Foundation.h>
#import "WeatherFetcher.h"
#interface City : NSObject {
}
#property (nonatomic, strong) NSString *cityName;
#property (nonatomic, strong) NSString *stateName;
#property (nonatomic, strong) UIImage *cityPicture;
#property (nonatomic, strong) NSString *weather;
#property (nonatomic, strong) NSMutableDictionary *weatherData;
-(NSString *)getWeather;
#end
UI calls getWeather by a button press to get the string value to be displayed on screen
#implementation City {
}
-(NSString *)getWeather {
//return self.weather;
NSString *info = #"";
WeatherFetcher *weatherFetcher = [[WeatherFetcher alloc] init];
[weatherFetcher fetchWeather:self.cityName];
self.weatherData = [weatherFetcher weatherData];
for (id element in self.weatherData) {
info = [info stringByAppendingString:[element description]];
info = [info stringByAppendingString:#"-->"];
info = [info stringByAppendingString:[self.weatherData valueForKey:[element description]]];
info = [info stringByAppendingString:#"\n"];
}
return info;
}
#end
What am I doing wrong here?
getWeather method in the city class gets called when a button is pressed and I'm trying to display this string in a text area. I don't have much experience with Objective C and this is my first app other than Hello World app.
Thank you!
Your WeatherFetcher is asynchronous (sendAsynchronousRequest:) - it sets a task to obtain the data and then returns (usually) before that data has been obtained. So when you try to access the weatherData immediately after the call to fetchWeather: it is not there yet.
You need to redesign your model to handle asynchronicity - getWeather cannot be synchronous. For example you could make fetchWeather: take a completion block to invoke when the data is available and have getWeather pass in a suitable block.

NSDictionary value replacing instead of adding in Plist

hi i tried to add values(book id,page number,notes) from NSdictionary to Plist but each time the new value replacing the previous one?but i need all values in plist my code for adding dictionary to plist is
NSString *bid=#"95";
NSString *pnum=#"12";
userNotes=[[NSMutableDictionary alloc]init];
[userNotes setValue:userNotesTextview.text forKey:#"notes"];
[userNotes setValue:bid forKey:#"bookid"];
[userNotes setValue:pnum forKey:#"pagenumber"];
userNotesView.hidden=YES;
_background.hidden = YES;
userNotesTextview.text=#"";
[self savingMetaData];
NSMutableArray *notes=[[NSMutableArray alloc]init];
[notes addObject:userNotes];
NSMutableDictionary *final=[[NSMutableDictionary alloc]init];
[final setValue:notes forKey:#"usernotes"];
[final writeToFile:metaDataPath atomically:YES];
and my plist look like
how can i solve this problem
Fetch the existing array from the plist as below, but first make sure you have copied you plist to Documents directory or, to some writable folder as below
NSFileManager *fileManager=[NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *docPath=[[paths objectAtIndex:0] stringByAppendingString:#"yourplist.plist"];
BOOL fileExists = [fileManager fileExistsAtPath: docPath];
NSError *error = nil;
if(!fileExists)
{
NSString *strSourcePath = [[NSBundle mainBundle] pathForResource:#"yourplist" ofType:#"plist"];
[fileManager copyItemAtPath:strSourcePath toPath:docPath error:&error];
}
NSString *path = docPath;
NSMutableDictionary *plistdictionary = [[NSMutableDictionary alloc]initWithContentsOfFile:path];
NSMutableArray *notes=[plistdictionary objectForKey:#"usernotes"];
if(notes==nil){
notes=[[NSMutableArray alloc] init];
}
NSString *bid=#"95";
NSString *pnum=#"12";
userNotes=[[NSMutableDictionary alloc]init];
[userNotes setValue:userNotesTextview.text forKey:#"notes"];
[userNotes setValue:bid forKey:#"bookid"];
[userNotes setValue:pnum forKey:#"pagenumber"];
[notes addObject:userNotes];
then finally
NSMutableDictionary *final=[[NSMutableDictionary alloc]init];
[final setValue:notes forKey:#"usernotes"];
[final writeToFile:docPath atomically:YES];
Note: You cannot write anything in MainBundle, so better to copy your plist to Documents directory and use from there..
because plist can store value with unique key only. if you try to save value with same key it will replace old one with new value. so always save new value with new key (eg. item0, item1, item3 etc.)
following line will store two usernote with key #"usernotes1" and #"usernotes2" respectively
[final setValue:notes forKey:#"usernotes1"];
[final setValue:notes forKey:#"usernotes2"];
Plist structure looks like this
You can create a UserNote model class.
#define kBookID #"bookid"
#define kPageNumber #"pageNumber"
#define kNotes #"notes"
#interface UserNote : NSObject
#property (nonatomic, copy) NSString *bookID;
#property (nonatomic, copy) NSString *pageNumber;
#property (nonatomic, copy) NSString *notes;
- (id)initWithDictionary:(NSDictionary *)dictionary;
+ (NSArray *)savedUserNotes;
- (void)save;
#end
Initialize
- (id)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self)
{
self.bookID = dictionary[kBookID];
self.pageNumber = dictionary[kPageNumber];
self.notes = dictionary[kNotes];
}
return self;
}
Find the document path of plist file in documents directory. If the plist file is not there create a new one and return the path.
+ (NSString *)userNotesDocumentPath
{
NSString *documentsPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"UserNotes.plist"];
NSFileManager *fileManger = [NSFileManager defaultManager];
if (![fileManger fileExistsAtPath:documentsPath])
{
NSString *bundleResourcePath = [[NSBundle mainBundle]pathForResource:#"UserNotes" ofType:#"plist"];
NSArray *userNotes = [NSArray arrayWithContentsOfFile:bundleResourcePath];
[userNotes writeToFile:documentsPath atomically:YES];
}
return documentsPath;
}
Fetches all saved usernotes from plist file.
+ (NSArray *)savedUserNotes
{
NSString *documentsPath = [self userNotesDocumentPath];
NSArray *savedNotes = [NSArray arrayWithContentsOfFile:documentsPath];
NSMutableArray *savedUserNotes = [#[] mutableCopy];
for (NSDictionary *dict in savedNotes) {
UserNote *note = [[UserNote alloc]initWithDictionary:dict];
[savedUserNotes addObject:note];
}
return savedUserNotes;
}
Saves a usenote to plist
- (NSDictionary *)userNoteDictionary
{
return #{kBookID:self.bookID,kPageNumber:self.pageNumber,kNotes:self.notes};
}
- (void)saveUserNotesToPlist:(NSArray *)userNotes
{
NSMutableArray *mutableUserNotes = [#[] mutableCopy];
for (UserNote *note in userNotes) {
NSDictionary *dict = [note userNoteDictionary];
[mutableUserNotes addObject:dict];
}
NSString *documentsPath = [UserNote userNotesDocumentPath];
[mutableUserNotes writeToFile:documentsPath atomically:YES];
}
#pragma mark - Save
- (void)save
{
NSMutableArray *savedNotes = [[UserNote savedUserNotes] mutableCopy];
[savedNotes addObject:self];
[self saveUserNotesToPlist:savedNotes];
}
In you viewController where user makes a note
- (IBAction)saveUserNoteButtonPressed:(UIButton *)button
{
UserNote *note = [UserNote new];
note.bookID = #"95";
note.pageNumber = #"12";
note.notes = self.userNotesTextview.text;
[note save];
}
Demo Source Code

How to load multiple languages to IVONA SDK - text to speech

I want to load multiple languages to use IVONA SDK with SSML for iPhone.
There is no documentation for use in Xcode/objective-C, only the SDK itself is given and several C/java examples.
How can you load multiple languages for text to speach with IVONA SDK for iOS?
EDIT 1: see my code below
load the voices at first:
- (NSInteger) loadVoice: (NSString*) vox {
if(voice != nil) {
XLog(#"(voice != nil)");
[voice unload];
voice = nil;
}
NSString *pathIvona = [[NSString alloc] initWithFormat:#"%#", vox];
self.paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [self.paths objectAtIndex:0];
self.path = [self.documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#", pathIvona]];
voice = [[IvonaVoice alloc] init:instance withLibrary:self.path withVox:self.path];
[pathIvona release];
if (voice == nil) {
XLog(#"Cannot load voice");
[self setTtsError: #"Cannot load voice"];
return 0;
}
[voice setParam:#"vol" withInteger: 99];
return 1;
}
trying to load multiple languages to one streamer with (the streamer is still nil, it doesnt change):
NSArray *allVoices = [self getAvaliableVoxes];
/**
* Here the streamer is still nil,
* i cant find the mistake here.
*
*/
IvonaStreamer *streamer = [[IvonaStreamer alloc] initWithVoices:allVoices
withText:[NSString stringWithContentsOfFile:self.path
encoding:NSUTF8StringEncoding error:&error] atSpeed:[NSNumber numberWithFloat:-1]];
Method getAvailableVoices:
- (NSArray*)getAvaliableVoxes {
XLog(#"-----------------------------------entered");
self.paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [self.paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager contentsOfDirectoryAtPath:[self.paths objectAtIndex:0] error:nil];
for (NSString *s in fileList){
//XLog(#"s: %#", s);
}
NSMutableArray *pathsIvona = [[NSMutableArray alloc] init];
NSEnumerator *e = [fileList objectEnumerator];
NSString *vox;
while (vox = [e nextObject]) {
if([[vox lastPathComponent] hasPrefix:#"vox_"]) {
XLog(#"vox: %#", vox);
[pathsIvona addObject: [vox lastPathComponent]];
XLog(#"pathsIvona: %#", pathsIvona);
}
}
XLog(#"pathsIvona: %#", pathsIvona);
return [pathsIvona autorelease];
}
How can you load multiple languages in one streamer on iOS with IVONA SDK?
perhaps the objects added to the array allVoices do not conform to the expected array of initWithVoices: ...