edit core data model objects in a loop - ios

I am trying to edit existing objects in Core Data storage. When i edit each object's attribute without a loop this works fine, but when I try to do it in a for loop, only my last object gets new attributes.
Here is the code I use to edit objects without a loop. This code works fine):
NSFetchRequest *songsRefreshRequest = [[NSFetchRequest alloc] initWithEntityName:#"Music"];
songsRefreshRequest.predicate = nil;
songsRefreshRequest.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"name"
ascending:YES
selector:#selector(localizedStandardCompare:)]];
NSError *frError;
NSArray *fetchedSongs = [self.context executeFetchRequest:songsRefreshRequest error:&frError];
fetchedSongs ? : NSLog(#"Error in fetch while refreshing songs: %#", [frError localizedDescription]);
NSString *song1path = [[NSBundle mainBundle] pathForResource:#"Beautiful-birds-song-in-the-morning" ofType:#"mp3"];
NSString *song2path = [[NSBundle mainBundle] pathForResource:#"Birds-singing-relaxation" ofType:#"mp3"];
NSString *song3path = [[NSBundle mainBundle] pathForResource:#"Morning Melody" ofType:#"mp3"];
Music *song1 = (Music *) [fetchedSongs objectAtIndex:0];
Music *song2 = (Music *) [fetchedSongs objectAtIndex:1];
Music *song3 = (Music *) [fetchedSongs objectAtIndex:2];
song1.name = #"Beautiful-birds-song-in-the-morning";
song2.name = #"Birds-singing-relaxation";
song3.name = #"Morning Melody";
song1.path = song1path;
song2.path = song2path;
song3.path = song3path;
Here is the code I use to edit song's attributes in a loop (code below somehow edit a path for only the last object (song3 in my case), other object's path attribute becomes NULL. And I can't figure out why):
for (Music *iterSong in fetchedSongs){
NSString *iterSongName = [iterSong valueForKey:#"name"];
iterSong.path = [[NSBundle mainBundle] pathForResource: iterSongName ofType:#"mp3"];
}
I have already tried to change for each to for (int i=0; i<[fetchedSongs count]; i++) this didn't help. Cycle repeats as many times as many songs are in the model and only changes the last song's path. Appreciate any help, thanks in advance!
P.S. The whole loop code:
for (Music *iterSong in fetchedSongs){
//Music *iterSong = (Music*) [fetchedSongs objectAtIndex:i];
NSLog(#"inerSong.name = %#", iterSong.name);
NSLog(#"inerSong.oldPath = %#", iterSong.path);
NSString *iterSongName = [iterSong valueForKey:#"name"];
NSString *iterSongPath = [[NSBundle mainBundle] pathForResource: iterSongName ofType:#"mp3"];
NSLog(#"iterSongPath (string) = %#", iterSongPath);
iterSong.path = iterSongPath;
NSLog(#"iterSong.newPath = %#", iterSong.path);
}
if ([self.context hasChanges]){
NSError *error;
if (![self.context save:&error]){
NSLog(#"error while saving context after refreshing song paths: %#", [error localizedDescription]);
}
}

First, I assume you run that loop inside the NSManagedObjectContext performBlock method. Second, you need to save your changes to your NSManagedObjects context after you edit your objects.
Objective-C:
NSError *error = nil;
if ([[self managedObjectContext] save:&error] == NO) {
NSAssert(NO, #"Error saving context: %#\n%#", [error localizedDescription], [error userInfo]);
}
Swift:
do {
try managedObjectContext.save()
} catch {
fatalError("Failure to save context: \(error)")
}

Problem solved this way:
I removed all the hyphens from files' names. And the code started to work fine with the same loop. Also I converted files from mp3 to wav. But I suppose that problem existed because file can't include hyphen in its name.
Thanks everyone who answered!

Related

Populated array not giving expected results

I've done a lot of object oriented programming in Java but im pretty new to objective C.
Am I doing the following properly.
Package.h
#interface Packages : NSObject
#property (nonatomic) NSArray *pictureArray;
#property (nonatomic) NSString *folderPath;
- (id)initWithPath:(NSString *)path;
-(NSArray *)getPackageItems;
-(NSString *)getFolderPath;
#end
Package.m
#implementation Packages
- (id)initWithPath:(NSString *)path
{
self = [super init];
if (self)
{
NSString *folderPath = [NSString stringWithFormat:#"%#/Objects/%#", [[NSBundle mainBundle] bundlePath], path]; //Path
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error: nil];
self.pictureArray = [fileList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"pathExtension IN %#", #"png", #"(content BEGINSWITH %#)", #"object_"]];
}
for (NSString *s in self.pictureArray) {
NSLog(#"%#", s);
}
return self;
}
-(NSArray *)getPackageItems{
return self.pictureArray;
}
-(NSString *)getFolderPath{
return self.folderPath;
}
#end
Code in question inside the viewdidload of one of my views
NSMutableArray *packages = [[NSMutableArray alloc] init];
for(id key in temp){
NSLog(#"key=%# value=%#", key, [temp objectForKey:key]);
Packages *tmp = [[Packages alloc] initWithPath:[temp objectForKey:key]];
[packages addObject:tmp];
}
so this for loop is iterating over a plist that I have. A series of paths.
for each path, it is creating an instance of Packages and adding it to an array of packages.
However, when do I do this
NSArray *something = [packages[1] getPackageItems];
I get an empty result back no matter what!
and even when I do this
NSLog(#"%#", [packages[0] getFolderPath]);
It prints out null.
What am I doing wrong.
EDIT
This is how the picture folder looks like
The code to pull it use to work when all of the pictures where in the Objects directory without any of the sub directories. I hope I edited the code properly to handle the sub dir
Edit 2
NSError *error;
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath error: &error];
NSLog(#"%#, %#", fileList , error);
on the line
NSString *folderPath = [NSString stringWithFormat:#"%#/Objects", [[NSBundle mainBundle] bundlePath], path]; //Path
which successfully prints
2014-03-23 21:25:32.200 ScrollBar[4475:60b] (
"object_eyes_0_0.png",
"object_eyes_10_1.png",
"object_eyes_10_2.png",
"object_eyes_10_3.png",
"object_eyes_10_4.png",
"object_eyes_10_5.png",
"object_eyes_10_6.png",
"object_eyes_10_7.png",
When I do
NSString *folderPath = [NSString stringWithFormat:#"%#/Objects/%#/objects", [[NSBundle mainBundle] bundlePath], path]; //Path
which outputs
2014-03-23 21:27:46.951 ScrollBar[4496:60b] (null), Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 260.)" UserInfo=0x8e2dda0 {NSUnderlyingError=0x8e2d020 "The operation couldn’t be completed. No such file or directory", NSFilePath=/Users/dev/Library/Application Support/iPhone Simulator/7.1/Applications/8B55D440-5727-471E-9BCC-1513C190740E/ScrollBar.app/Objects/object_eye_0_0/objects, NSUserStringVariant=(
Folder
)}
But as you can see in the image above, the file structure does exist.
Solution:
I accepted an answer even though it wasnt the real answer, it was the clear path to find out what was wrong.
The problem was that you can not have referenced folders containing sub folders using the code provided. I just many folders.
in your initWithPath:, you have NSString *folderPath = which declare a local variable and assign some value to it. However you did not save the value so self.folderPath is nil
- (id)initWithPath:(NSString *)path
{
self = [super init];
if (self)
{
self.folderPath = [NSString stringWithFormat:#"%#/Objects/%#", [[NSBundle mainBundle] bundlePath], path];
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath error: nil];
self.pictureArray = [fileList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"pathExtension IN %#", #"png", #"(content BEGINSWITH %#)", #"object_"]];
}
for (NSString *s in self.pictureArray) {
NSLog(#"%#", s);
}
return self;
}
for logging error
NSError *error;
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath error: &error];
NSLog(#"%#, %#", fileList , error);
NEVER do NSLog([Someclass someMethod]), use NSLog(#"%#", [Someclass someMethod]) instead

Import .ics File and show in Calendar or UITableView

I retrieve an .ics file from a certain url. I'd like to present the information of this file in a calendar and/or list view in my own app. I had a look at iCal4Objc("https://github.com/cybergarage/iCal4ObjC") and parsed the information like this:
-(NSMutableArray *)getPlanFromURL:(NSURL *)url {
NSMutableArray *planEntries = [[NSMutableArray alloc]init];
NSString *storePath = [self loadICSAndReturnPathFromURL:url];
CGICalendar *parserCalendar = [[CGICalendar alloc]initWithPath:storePath];
for(CGICalendarObject *planObject in [parserCalendar objects]) {
for(CGICalendarComponent *component in [planObject components]) {
for (CGICalendarProperty *icalProp in [component properties]) {
NSString *icalPropName = [icalProp name];
NSLog(#"%#",icalPropName);
if([icalPropName isEqualToString:SUMMARY]) {
[self.summaryArray addObject:[icalProp value]];
}
else if([icalPropName isEqualToString:LOCATION]) {
[self.locationArray addObject:[icalProp value]];
}
else if([icalPropName isEqualToString:CATEGORIES]) {
[self.categoryArray addObject:[icalProp value]];
}
else if([icalPropName isEqualToString:DTSTART]) {
[self.startArray addObject:[icalProp dateValue]];
}
else if([icalPropName isEqualToString:DTEND]) {
[self.endArray addObject:[icalProp dateValue]];
}
}
}
}
for(int i = 0;i<[self.summaryArray count];i++) {
DECalEntry *entry = [[DECalEntry alloc]init];
entry.summary = [self.summaryArray objectAtIndex:i];
entry.roomInformation = [self.locationArray objectAtIndex:i];
entry.category = [self.categoryArray objectAtIndex:i];
entry.startDate = [self.startArray objectAtIndex:i];
entry.endDate = [self.endArray objectAtIndex:i];
if ([entry.category isEqualToString:#"Prüfung"]) {
entry.isExam = true;
}
else entry.isExam = false;
[planEntries addObject:entry];
}
return planEntries;
}
-(NSString *)loadICSAndReturnPathFromURL:(NSURL *)url {
NSURLRequest * urlRequest = [NSURLRequest requestWithURL:url];
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
if (error == nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *storePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"planData.ics"];
[data writeToFile:storePath atomically:YES];
return storePath;
}
NSLog(#"Error: %#",[error localizedDescription]);
return nil;
}
Since this is not very clean and it would be a pain to also implement UITableView and a calendar view to illustrate the parsed data i asked me whether there exists a framework that one of you knows which already can handle .ics files and shows them accordingly.
If you have an idea how to solve this issue less complicated and/or with less effort i would be really grateful.
Also have a look at my comment. At the moment the rrule property is not considered at all. But this is very important since it shows me if a event is repeated, until it is repeated and so on...
Nevermind i got it working myself by parsing the rrule property like i did it with the other properties and constructed a method which creates the right amount of objects i need by following the information that this property contains. Well i just think this was the only way because apparently the is no framework for importing and parsing .ics files. When i finish my project i might give it a shot for people who might face this one day.
To my knowledge there is no framework or control provided by Apple that displays .ics files, but once you construct an EKEvent, there is:
https://developer.apple.com/library/ios/documentation/EventKitUI/Reference/EKEventEditViewControllerClassRef/Reference/Reference.html#//apple_ref/doc/uid/TP40009571
Specifically, you want to take a look at EventKitUI.framework.

Song doesn't play when method called from another class

I'm trying to play a song in my application. When the the code to play a song is put right away in the controller it runs good.
But when i put the code in a class, call the class then call the method to play the song, nothing happens ? If someone have a clue please feel free to help.
here is the code to play a song
-(void)randomSound{
NSLog(#"sound");
NSString * path;
NSError * err;
NSString *name;
NSArray *names = [[NSArray alloc] initWithObjects:#"1up.wav", #"mario02.dsp.wav", #"mario04.dsp.wav", #"mario06.dsp.wav", #"mrf.dsp.wav", nil];
name = [names randomObject];
path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:name];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSURL * url = [NSURL fileURLWithPath:path];
self.snd = [[AVAudioPlayer alloc] initWithContentsOfURL:url
error:&err] ;
if (! self.snd) {
NSLog(#"data named '%#' had error %#", name, [err localizedDescription]);
} else {
NSLog(#"playing");
[self.snd prepareToPlay];
[self.snd play];
}
} else {
NSLog(#"data file '%#' doesn't exist at '%#'", name, path);
}
}
The way i call the method
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"YAHOO"])
{
YahooViewController *YH = [[YahooViewController alloc] init];
[YH randomSound];
}
The random method in case someone would like to know whats in it
-(id)randomObject {
NSUInteger myCount = [self count];
if (myCount)
return [self objectAtIndex:arc4random_uniform(myCount)];
else
return nil;
}
After discussion in comments it was identified the issue was URL encoding.
Check out this question / answer which will show you how to URLEncode a string:
How do I URL encode a string

CHCSV Parser error: No known class method for selector 'arrayWithContentsOfCSVFile:encoding:error:'

When attempting to use the CHCSV parser like this:
#import "CHCSVParser.h"
....
- (IBAction)hi:(id)sender {
NSString *path = [[NSBundle mainBundle] pathForResource:#"nood" ofType:#"csv"];
NSError *error = nil;
NSArray *rows = [NSArray arrayWithContentsOfCSVFile:path encoding:NSUTF8StringEncoding error:&error];
if (rows == nil) {
//something went wrong; log the error and exit
NSLog(#"error parsing file: %#", error);
return;
}
}
I get the error:
No known class method for selector arrayWithContentsOfCSVFile:encoding:error:
I have included the CHCSV header but this error still happens.
This question is the exact same as this one but it never got answered so please don't mark it as a duplicate.
The header from github appears to have no such method. Your choices appear to be:
+ (instancetype)arrayWithContentsOfCSVFile:(NSString *)csvFilePath;
+ (instancetype)arrayWithContentsOfCSVFile:(NSString *)csvFilePath options:(CHCSVParserOptions)options;
Note that neither has an encoding: argument.
As this question is asked long back but still i will add
These methods has been deprecated which Dev has already rewritten in .h file.
Instead you have to use
- (IBAction)hi:(id)sender {
NSString *path = [[NSBundle mainBundle] pathForResource:#"nood" ofType:#"csv"];
NSArray *rows = [NSArray arrayWithContentsOfCSVURL:[NSURL fileURLWithPath:path] options:options];
if (rows == nil) {
//something went wrong; log the error and exit
NSLog(#"error parsing file: %#", error);
return;
}
}

Delete oldest file in directory iOS

For some reason this method that I have written doesn't get rid of the oldest file in a directory even though everything seems fine from a logic point of view. Is there something subtle I am missing?
+(void)removeOldestFileFromDir:(NSURL *)dir forFileManager:(NSFileManager *)fm{
NSError *error = nil;
NSArray *contents = [fm contentsOfDirectoryAtPath:[dir path] error:&error];
NSArray *jpgFiles = [contents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self ENDSWITH '.jpg'"]];
NSDate *oldest = [NSDate date];
NSString *oldestFileName = nil;
for (NSString *f in jpgFiles) {
NSString *photoPath = [[dir path] stringByAppendingPathComponent:f];
NSDate *created = [[fm attributesOfItemAtPath:photoPath error:&error] objectForKey:#"NSFileCreationDate"];
if([created compare:oldest] == NSOrderedAscending){
oldestFileName = [NSString stringWithString:photoPath];
}
}
[fm removeItemAtPath:oldestFileName error:&error];
}
I've checked the error and it's alway (null) and the file that gets deleting is seemingly random - sometimes it's the newest, sometimes it's another one.
You forget to set oldest variable inside of your if.
It should be like that:
if([created compare:oldest] == NSOrderedAscending){
oldestFileName = [NSString stringWithString:photoPath];
oldest = created; // !!! This is what is missing
}

Resources