NSMutableString and (character)-encoding issue: getting \U00fc in case of ü - objective-c

i am fetching my entity from coreData and saving the result of fetchrequest to an NSMutableString for text to speech.
self.ttsInboxCards = [[NSMutableString alloc] initWithString:#""];
[self.ttsInboxCards appendString:[[entitySetsCards valueForKey:#"cardTitle"] description]];
And in NSLog i am getting this values:
F\U00fcr | schl\U00e4ge | zuh\U00f6ren
which should be:
Für | schläge | zuhören
I have tried a lot of things to get the correct encoding, for example with:
stringWithUTF8String:
and so on, but nothing worked.
How can i prevent this issue?
EDIT 1:
I am getting the values from coreData like this:
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"EntitySetsCardsInbox" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *inboxPred = [NSPredicate predicateWithFormat:#"archived == 0 AND cardId != 0"];
[fetchRequest setPredicate:inboxPred];
NSSortDescriptor *sortDescriptor2 = [[[NSSortDescriptor alloc] initWithKey:sortString ascending:sortAsc selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:sortDescriptor2, nil] autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *cardTitles = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
[self.ttsInboxCards appendString:[[cardTitles valueForKey:#"cardTitle"] description]];
TextToSpeech
if (isSpeaking) {
[vocalizer cancel];
isSpeaking = NO;
}
else {
isSpeaking = YES;
vocalizer = [[SKVocalizer alloc] initWithLanguage:#"de_DE" delegate:self];
[vocalizer speakString:tmp];
}

I wrote:
cardTitles is an array. So, invoking -valueForKey: on it yields an
array built by invoking -valueForKey:#"cardTitle" on each element.
Then you're asking that array for its description. It's very likely to
do formatting of its contents.
brush51 wrote:
componentsJoinedByString: worked and solved the issue with encoding.
now i have to split them correctly so that i can use it cleanly for
text to speech. can you make an answer with that so i can mark this
question as answered and others can find it faster

Make that Caps U with smaller one and try.

Related

Sorting in Core Data with Multiple Values

i have list of brands stored in Core Data, each brand is associated with multiple contents. The contents have a flag called downStatus which is used to denote whether a content is downloaded or not. The following method is used to fetch all the brands from Core data sorted with brand name
-(void)getDownloadedBrands{
AppDelegate *aAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *aBrands = [[NSMutableArray alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"Brand" inManagedObjectContext:aAppDelegate.managedobjectcontext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *sort=[[NSSortDescriptor alloc]initWithKey:#"brandName" ascending:YES];
//NSSortDescriptor *sort1=[[NSSortDescriptor alloc]initWithKey:#"downStatus" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
aBrands =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request error:nil];
[request release];
[sort release];
NSLog(#"%#",aBrands);
brands = [[NSMutableArray alloc]initWithArray:aBrands];
aAppDelegate.dbBrandArr = brands;
[self loadGridView];
}
Now i want to sort using the downStatus which is in the Content. So it will be like, downloaded brands in Alphabetical Order and then Un-Downloaded brands in Alphabetical order. The downStatus takes two values 1 for downloaded 0 for not downloaded. Please help.
One way to do it is by making 2 fetchRequests to CoreData using the NSPredicate with value 1/0 on downStatus property and using the same alphabetical sortDescriptor.
Now create a new Array by adding the 0 array to the 1 array. In your code it would look something like this:
-(void)getDownloadedBrands{
AppDelegate *aAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
//2 arrays
NSMutableArray *aBrands0 = [[NSMutableArray alloc] init];
NSMutableArray *aBrands1 = [[NSMutableArray alloc] init];
//set entity en make requests
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Brand" inManagedObjectContext:aAppDelegate.managedobjectcontext];
NSFetchRequest *request0 = [[NSFetchRequest alloc] init];
NSFetchRequest *request1 = [[NSFetchRequest alloc] init];
[request0 setEntity:entity];
[request1 setEntity:entity];
//create sortDescriptor alphabetically
NSSortDescriptor *sort=[[NSSortDescriptor alloc]initWithKey:#"brandName" ascending:YES];
//create predicates on downStatus property
NSPredicate *predicate0 = [NSPredicate predicateWithFormat:#"downStatus == %#", [NSNumber numberWithBool:0]];
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:#"downStatus == %#", [NSNumber numberWithBool:1]];
//set predicates to the requests
[request0 setPredicate:predicate0];
[request1 setPredicate:predicate1];
//set sortDescriptor to both requests
[request0 setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
[request1 setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
//fetch arrays with downStatus 1/0
aBrands0 =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request0 error:nil];
aBrands1 =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request1 error:nil];
//release requests // NOT USING ARC??
[request0 release];
[request1 release];
[sort release];
//log results
NSLog(#"aBrands0: %#",aBrands0);
NSLog(#"aBrands1: %#",aBrands1);
//add object 0 array to 1 array
NSArray *combinedArray = [aBrands1 arrayByAddingObjectsFromArray:aBrands0];
//copy array to brands
brands = [[NSMutableArray alloc]initWithArray:combinedArray];
//set property on appDelegate
aAppDelegate.dbBrandArr = brands;
//reload tableView
[self loadGridView];
}
-- edit, adding answer for NSDictionary with downStatus key
-(void)getDownloadedBrands{
AppDelegate *aAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *aBrands = [[NSMutableArray alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Brand" inManagedObjectContext:aAppDelegate.managedobjectcontext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *sort=[[NSSortDescriptor alloc]initWithKey:#"brandName" ascending:YES];
//NSSortDescriptor *sort1=[[NSSortDescriptor alloc]initWithKey:#"downStatus" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
aBrands =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request error:nil];
NSMutableArray *aBrands0 = [[NSMutableArray alloc] init];
NSMutableArray *aBrands1 = [[NSMutableArray alloc] init];
for (NSDictionary *dict in aBrands) {
if ([dict valueForKeyPath:#"downStatus"] == YES)
{
//add to 1 array
[aBrands1 addObject:dict];
}
else
{
//add to 0 array
[aBrands0 addObject:dict];
}
}
//sort arrays
NSArray * array1 = [aBrands1 sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
NSArray * array0 = [aBrands0 sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
NSArray * allArray = [aBrands1 arrayByAddingObjectsFromArray:aBrands0];
//combine arrays
//copy array to brands
brands = [[NSMutableArray alloc]initWithArray:combinedArray];
//set property on appDelegate
aAppDelegate.dbBrandArr = brands;
//reload tableView
[self loadGridView];
[request release];
[sort release];
NSLog(#"%#",aBrands);
}
If you plan to use the fetch result in a UITableViewController, you could use the sectionNameKeyPath of your fetchedResultsController for the downStatus and keep your sort descriptor for the brand name. Can look like this:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"customSectionTitle" cacheName:nil];
Place this in the header file of your NSManagedObject :
-(NSString*)customSectionTitle;
And this in .m :
-(NSString*)customSectionTitle{
if ([downStatus boolValue] == YES) {
return #"Downloaded";
}
else {return #"Not Downloaded";}
}
If you do not plan to use a fetchedResultsController, just sort first by downStatus and then by brand name.

to set default value when core data fetch result is null

I am using simple core data fetch request code.
- (NSMutableArray *) read_cd
{
NSError *error = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"List_CD" inManagedObjectContext:cd_Context];
[request setEntity:entity];
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:#"last_date" ascending:NO];
NSArray *sortDescriptor = [[NSArray alloc] initWithObjects:sd, nil];
[request setSortDescriptors:sortDescriptor];
NSMutableArray *mutableFetchResults = [[cd_Context executeFetchRequest:request error:&error] mutableCopy];
if(mutableFetchResults == nil){
//Handle the error
}
return mutableFetchResults;
}
and I'm using return value like this
MSMutableArray *now_cd = self.read_cd;
cell output for {
cell.label1.text = [[now_cd objectAtIndex:i] cd_title];
cell.label2.text = [[now_cd objectAtIndex:i] cd_auth];
}
I want to set default value when executeFetchRequest is null.
so I can continue to use an existing output module.
I don't know how to make a method like that
[[object objectAtIndex:i] instance]

an NSPredicate for selecting a row with maximum value by group

I'm using Core Data to store entities in the form
TrackerEntry
username
timestamp
I want to select the latest record for each user. Using sql it would be something like
SELECT MAX(timestamp) FROM Log GROUP BY username
Is there anyway to create an NSPredicate to do this?
I would do it using NSExpression. This bit of code below won't work for you because you will have to group by username too, but it's a start for the best way of doing this without having to fetch everything. You want to perform the max and group in the db, not in memory - as it will be faster:
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
// Expression for the max
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"timestamp"];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.coreDataStack.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];
NSExpression *valueSumExpression = [NSExpression expressionForFunction:#"max:" arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[[NSExpressionDescription alloc] init] autorelease];
[expressionDescription setName:#"maxTimestamp"];
[expressionDescription setExpression:valueSumExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Filter
//NSPredicate *pred = [NSPredicate predicateWithFormat:#" your predicate here"];
//fetchRequest.predicate = pred;
NSArray *results = [self.coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
if([results count] == 0) {
} else {
// [[results objectAtIndex:0] valueForKey:#"maxTimestamp"];
}
This worked for me, but it is a loop. First you have to get the unique names into an array.
NSFetchRequest *nameRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
nameRequest.entity = entity;
nameRequest.resultType = NSDictionaryResultType;
[nameRequest setPropertiesToFetch:[NSArray arrayWithObject:[[entity propertiesByName] objectForKey:#"name"]]];
NSArray *allNames = [self.managedObjectContext executeFetchRequest:nameRequest error:nil];
names = [allNames valueForKeyPath:#"#distinctUnionOfObjects.name"];
[nameRequest release];
NSLog(#"%#", names);
Not very efficient or convenient. After all, Core Data is not a database but an object graph.
Then you can loop through these and fetch just the top one.
NSMutableArray *mutableResults = [NSMutableArray array];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *numberSort = [NSSortDescriptor sortDescriptorWithKey:#"number" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:numberSort];
request.fetchLimit = 1;
for (NSString *s in names) {
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name = %#", s];
request.predicate = pred;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:nil];
[mutableResults addObject:[results objectAtIndex:0]];
}
[request release];
NSLog(#"%#", mutableResults);

NSSortDescriptor for NSFetchRequest sorting unexpectedly

My entity has a property (sortOrder) that is of the type Decimal(NSDecimalNumber) but when I execute a fetch request using that property as a key, I get back results in a seemingly random order. If I output the value of the property I get really strange values until I get it's intValue.
Example: The first run produces this result. The first value is the raw value of the property. The second is the intValue, the actual value of the property when I created the object - or at least I thought.
85438160 10
74691424 20
Second run...
85333744 10
85339168 20
Third...
85263696 20
85269568 10
What the hell?
Fetch Request:
NSMutableArray *cats = [[NSMutableArray alloc] initWithArray:[CoreDataHelper searchObjectsInContext:#"RestaurantMenuCategory":nil:#"sortOrder":YES:NO:nil]];
Here is the searchObjectsInContext method from my CoreDataHelperClass:
+(NSMutableArray *) searchObjectsInContext: (NSString*)entityName : (NSPredicate *)predicate : (NSString*)sortKey : (BOOL)sortAscending : (BOOL)distinct : (NSString*)distinctProperty
{
RestaurantController *ctrl = [RestaurantController sharedRestaurantController];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:ctrl.managedObjectContext];
[request setEntity:entity];
if(distinct==YES){
[request setReturnsDistinctResults:YES];
}
if(distinctProperty!= nil){
[request setPropertiesToFetch :[NSArray arrayWithObjects:distinctProperty,nil]];
}
if(predicate != nil){
[request setPredicate:predicate];
}
if(sortKey != nil){
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
}
NSError *error;
NSMutableArray *mutableFetchResults = [[[ctrl.managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease];
[request release];
return mutableFetchResults;
}
You cannot use a %d format to print out an NSDecimalNumber.
NSDecimalNumber is an Objective-C object; %d is for printing "int"s. If you use the %d format string, it will probably print something non-useful like the address of the object; use "%#" instead.

displaying in a UITableView CoreData objects ordered in a Set

I have difficulties displaying objects coming from CoreData in a tableView.
I have 2 sorts of entities : Sample and SampleList. What is important to know is that a SampleList has an attribute sampleSet which is a set of samples (entity of Sample)
First I succeeded in displaying every SampleList. Here is viewDidLoad:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SampleList" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastSampleDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle error
}
[self setSampleListArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
Once I click on a row in my tableView, I would like to display in another UITableView every sample from the SampleList selected.
I thought that I could pass to the subview SampleList mySampleList. But then, I don't know what to do with it as it is not organized.
How can I return an ordered array of Sample (ordered by dateSample attribute for example) ?
Thank you for your time !
You can just use NSSet and NSArray methods on sampleSet to get an ordered array:
sortedArray = [[sampleSet allObjects] sortedArrayUsingSelector:#selector(compare:)];
or if you want to specify particular sort descriptors instead of the regular "compare" method:
sortedArray = [[sampleSet allObjects] sortedArrayUsingDescriptors:sortDescriptors];