In .plist file I keep NSURLs of audio files from iPod library. I need to initialize MPMediaItemCollection items by these urls.
How can I do that? Thanks.
I found the solution
keep it here, if someone will need same thing once
MPMediaQuery *everything = [[MPMediaQuery alloc] init];
NSArray *itemsFromGenericQuery = [everything items];
for (MPMediaItem *song in itemsFromGenericQuery)
{
if ([savedUrl isEqual:[song valueForProperty:MPMediaItemPropertyAssetURL]])
{
ownMediaItemCollection = [MPMediaItemCollection collectionWithItems: [NSArray arrayWithObject:song]];
}
}
[everything release];
Related
In my application I need to create a copy of NSMutableArray. Currently I am using mutableCopy method. But when I modify the copied array the original one is also modified. Please tell me How to create a new copy NSMutableArray.
Here is the code
delegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
self.mainImagesArray = [[NSMutableArray alloc]initWithArray:[delegate.arrayForCarCaptureImages mutableCopy]];
and here i am modifying
UIImage *filteredImage =[[[[self.mainImagesArray objectAtIndex:i]valueForKey:valueVheck] objectAtIndex:j] copy];
filteredImage =[filteredImage brightness:(1+sliderValue-0.5)];
[[[self.mainImagesArray objectAtIndex:i]valueForKey:valueVheck]removeObjectAtIndex:j];
[[[self.mainImagesArray objectAtIndex:i] valueForKey:valueVheck]insertObject:filteredImage atIndex:j];
After execution the arrayForCarCaptureImages also modified automatically.
You need to create a deep copy. From what I understand, you're creating a copy of the NSMutableArray itself without making copies of it's individual elements.
From what I see in the code you've written:
You're abusing the delegation pattern
Your code is not readable. Try passing it along to another developer, I bet you'll get slapped very fast :)
Here's an example of a classic case of deep copying:
NSArray *numbersArr = #[#1,#2,#3];
NSMutableArray *numbersArrCopy = [NSMutableArray array];
for (NSNumber *num in numbersArr) {
[numbersArrCopy addObject:[num copy]];
}
An easier approach:
NSArray *numbersArr = #[#1,#2,#3];
NSArray *numbersArrCopy = [[NSArray alloc] initWithArray:numbersArr copyItems:YES];
This is of course different than just:
NSArray *numbersArr = #[#1,#2,#3];
NSArray *numbersArrCopy = [numbersArr copy];
Have you tried:
NSArray *copiedArray = [[NSArray alloc] initWithArray:[otherArray copy]];
Try this code in your project:
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"one", #"two", #"three", nil];
NSMutableArray *copiedArray = [array mutableCopy];
[array addObject:#"four"];
NSLog(#"copied %#", copiedArray);
MutableCopy will not perform deep copy. You have to do it manually as given,
NSMutableArray *arrayCopy = [NSMutableArray array];
for (id element in arraySource)
[arrayCopy addObject:[element mutableCopy]]; //or [arrayCopy addObject:[element copy]];
You code is hardly readable. See if this is working
delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.mainImagesArray = [[NSMutableArray alloc]initWithArray:delegate.mainImagesArray
copyItems:YES];
UIImage *filteredImage = self.mainImagesArray[i][valueVheck][j];
filteredImage = [filteredImage brightness:(1+sliderValue-0.5)];
[self.mainImagesArray[i][valueVheck]replaceObjectAtIndex:j
withObject:filteredImage];
I've read that this error comes from memory-management issues such as sending a message to an object which has been released. I am getting the error right after the comment "output information about songs in the 'info' array", in the first line of that second 'for' section. Is the info array not storing the objects that I am giving it in the first 'for' section?
Any other ideas?
MPMediaQuery *query = [[MPMediaQuery alloc] init]; //query iPod library
NSMutableArray *info; //create array to hold songs that fit
NSArray *allSongs = [query collections];
//only add those songs which have not
//been played since last login
for (MPMediaItem *recent in allSongs) {
NSDate *lastPlayed = [recent valueForProperty:MPMediaItemPropertyLastPlayedDate];
BOOL uploadInfo = [[PlayedSinceLastLogin alloc] initWithLastPlayedDateOfSong:lastPlayed] ;
if (uploadInfo == YES) {
[info addObject:recent];
}
}
//output information about songs
//in the 'info' array
for (MPMediaItem *played in info) {
NSString *playCount = [played valueForProperty:MPMediaItemPropertyPlayCount];
NSString *lastPlayed = [played valueForProperty:MPMediaItemPropertyLastPlayedDate];
NSString *songTitle =
[played valueForProperty: MPMediaItemPropertyTitle];
NSString *artistName =
[played valueForProperty: MPMediaItemPropertyArtist];
NSString *albumName =
[played valueForProperty: MPMediaItemPropertyAlbumTitle];
NSLog (#"\n %# by %#, from album %#, played since last login.\nLast Played:%#.\nTotal Play Count: %#.", songTitle, artistName, albumName, lastPlayed,playCount);
}
It doesn't look like you've ever actually created an instance of NSMutableArray for info to point to, so the bad access error is probably due to attempting to treat some random bit of memory as an initialized object.
Change
NSMutableArray *info;
to
NSMutableArray *info = [NSMutableArray array];
i want to populate the tablecell with title and imageurl from xml list.
i manage to store the title (NSMutableDictonary *sections )and imageURL (NSMutableDictonary *sectionsImg) into 2 NSMutableDictionary respectively.
/*******This is in viewDidLoad***/
Directory *allDirectory = [appDelegate.directories objectAtIndex:0];
for (allDirectory in appDelegate.directories)
{
NSDictionary *dica = [NSDictionary dictionaryWithObject:allDirectory.dirTitle forKey:#"dirTitle"];
NSDictionary *dico = [NSDictionary dictionaryWithObject:allDirectory.imageURL forKey:#"imageURL"];
[dirName addObject:dica];
[dirImage addObject:dico];
//NSLog(#"dic of items : %#",dirImage);
}
for (allDirectory in appDelegate.directories)
{
//retrieve the first letter from every directory title (dirTitle)
NSString * c = [allDirectory.dirTitle substringToIndex:3];
NSString * m = allDirectory.imageURL;
found = NO;
find = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:c])
{
found = YES;
}
}
for (NSString *stra in [self.sectionsImg allKeys])
{
if([stra isEqualToString:m])
{
find = YES;
}
}
if (!found)
{
[self.sections setValue:[[NSMutableArray alloc]init] forKey:c ];
[self.sectionsImg setValue:[[NSMutableArray alloc]init] forKey:m];
}
if (!find)
{
[self.sectionsImg setValue:[[NSMutableArray alloc]init] forKey:m];
}
}
for (NSDictionary *directory in dirName)
{
[[self.sections objectForKey:[[directory objectForKey:#"dirTitle"] substringToIndex:3]] addObject:directory];
//NSLog(#"hehehe have : %#",sections);
}
for (NSDictionary *directoryImg in dirImage)
{
//[[self.sectionsImg objectForKey:[[directoryImg objectForKey:#"imageURL"] substringFromIndex:0]] addObject:directoryImg];
[[self.sectionsImg objectForKey:[directoryImg objectForKey:#"imageURL"]] addObject:directoryImg];
//NSLog(#"HOHOHO have : %#",sectionsImg);
}
And on cellForRowAtIndexPath i declare a dictionary
NSDictionary *dictionary = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [dictionary objectForKey:#"dirTitle"];
but when i tried to declare a dictionary for imageURL
NSDictionary *dictionaryImg = [[self.sectionsImg valueForKey:[[[self.sectionsImg allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
it gives me a error :
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
any idea why? the logic is supposed to be the same where xml title and url can be retrieve and be displayed. Title is retrievable but imageURL is not. Help is deeply appreciated !
You are trying to sort an array... except for the fact your array isn't an array, but a NSDictionary.
Your code isn't the best at the moment. Your getting the idea of Dictionaries wrong and may be confusing them with arrays, so my best guess is your quite new to programming into objective-c.
You have two lists of things, if I'm not mistaken. The first list is the list of names, and the second list is an image corresponding with that name.
Below I'm going to do two things:
Firstly, I'm giving you two ways on how to fix your problem. It has a sample code included and gives you a small explanation with it. The possibility exist you don't understand parts of what I describe. In that case, you should;
Check out the link I described below the two solutions. It has a tutorial which makes you understand everything about arrays, dictionaries, tables and, as a bonus, XML-parsing.
So, in my opinion, you can do two things:
The first one is using an array of NSDictionaries. You'd be using a code which looks like:
NSMutableDictionary *itemOne = [[NSMutableDictionary alloc] init];
NSMutableDictionary *itemTwo = [[NSMutableDictionary alloc] init];
NSMutableArray *listOfAll = [[NSmutableArray alloc] init];
NSString *itemOneName = [[NSString alloc] initWithFormat:#"This is picture 1"];
NSString *itemTwoName = [[NSString alloc] initWithFormat:#"This is picture 2"];
NSData *imageOneData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://myurl/mypic1.jpg"]];
NSData *imageTwoData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://myurl/mypic2.jpg"]];
UIImage *itemOneImage = [UIImage imageWithData: imageOneData];
UIImage *itemTwoImage = [UIImage imageWithData: imageTwoData];
[itemOne setObject:itemOneNameString forKey:#"Name"];
[itemOne setObject:itemOneImage forKey:#"Image"];
[itemTwo setObject:itemTwoNameString forKey:#"Name"];
[itemTwo setObject:itemTwoImage forKey:#"Image"];
[listOfAll addObject:itemOne];
[listOfAll addObject:itemTwo];
Anything can be filled using that array. Just use something with a for-loop to iterate through your array.
for (int i = 0; i < [listOfAll count]; i++)
{
NSMutableDictionary *currentItem = [[NSMutableDictionary alloc] initWithDictionary:[listOfAll objectAtIndex:i]];
//Do something with that current item
}
You can also use that index in your tableView. In that case, you have to use your variable section instead of i to get your desired index.
The second one is using two arrays. Imagine you get an image named imageOne with the text imageName. Then you should use:
NSMutableArray *nameList = [[NSMutableArray alloc] init];
[nameList addObject: imageName];
NSMutableArray *imageList = [[NSMutableArray alloc] init];
[imageList addObject: imageOne];
If you want to use a certain item out of those lists, you just have to use the same indexnumber.
For example:
[theTitleLabel setText:[[NSString alloc] initWithFormat:#"%#", [nameList objectAtIndex:x]]];
[theImageView setImage:[imageList objectAtIndex:x]];
Make sure the x's are the same number.
I understand this is all a lot of information, especially if you're new to Objective - C. A tutorial exists which gives you a lot of information about how to use arrays, dictionaries and table views. As a bonus, you get to know a little about XML-parsing.
I suggest you walk through that tutorial and do everything and read everything it says. This should give you a nice start into the world of programming in iPhones.
Good luck!
I'm looping through all the songs from an iPhone's music library using the following code:
NSArray * songs = [[NSArray alloc] initWithArray:[[MPMediaQuery songsQuery] collections]];
for (MPMediaItemCollection * item in songs){
NSString * persistentID = [[[item representativeItem] valueForProperty:MPMediaItemPropertyPersistentID] stringValue];
// Do something with it.
}
[songs release];
Pretty basic stuff.
I'm getting the PersistentID as an NSString because I need to write it to an XML file (for transmission over a network to another device). Hence the reason I can't just leave it as an NSNumber.
The other device will then ask for the iPhone to play a track by transmitting the PersistentID back again.
At this point, the iPhone has an NSString of the PersistentID of the track it should play.
It would be combersome to loop through every song again and compare PersistentIDs until I find the track I want, so I'm trying to use the MPMediaPropertyPredicate to have the iPhone search for me.
I'm using the following code for the search:
MPMediaPropertyPredicate * predicate = [MPMediaPropertyPredicate predicateWithValue:persistentID forProperty:MPMediaItemPropertyPersistentID];
MPMediaQuery * songsQuery = [[MPMediaQuery alloc] init];
[songsQuery addFilterPredicate:predicate];
if ([[songsQuery items] count]){
MPMediaItem * item = [[songsQuery items] objectAtIndex:0];
// Play item.
}
[songsQuery release];
Where persistentID is the NSString from earlier.
Weirdly, this works for some songs, not for others. i.e, sometimes the items array is not empty, even though I'm passing an NSString, not an NSNumber.
I'm wondering if there's a way to convert my NSString back to the NSNumber it came from, and how I can do that.
UPDATE: I've tried the NSNumberFormatter, I've also tried something like:
[NSNumber numberWithFloat:[persID floatValue]];
I've tried all the standard ways of doing it without prevail.
This is working pretty well, no problems so far:
unsigned long long ullvalue = strtoull([persistentID UTF8String], NULL, 0);
NSNumber * numberID = [[NSNumber alloc] initWithUnsignedLongLong:ullvalue];
MPMediaPropertyPredicate * predicate = [MPMediaPropertyPredicate predicateWithValue:numberID forProperty:MPMediaItemPropertyPersistentID];
[numberID release];
// And so on.
Hope this helps anyone else who ran into this problem.
If I understand you correctly, you're trying to convert an NSString to an NSNumber. To do this, you can use a NSNumberFormatter. Take a look at the numberFromString: method.
NSNumberFormatter Class Reference
I just had to do the same thing. The Query Predicate for MPMediaItemPropertyPersistentID has to be passed in as NSNumber. I found this answer on converting NSString to NSNumber from another StackOverflow post:
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * persistentIDasNumber = [f numberFromString:persistantID];
[f release];
MPMediaPropertyPredicate * predicate = [MPMediaPropertyPredicate predicateWithValue:persistentIDasNumber forProperty:MPMediaItemPropertyPersistentID];
This worked for me.
I ran into something very similar and worked out the following:
NSNumber *musicIdentifier = [[[NSNumberFormatter alloc] init] numberFromString: persistentID];
MPMediaQuery *query = [[MPMediaQuery alloc] initWithFilterPredicates:[NSSet setWithObject:[MPMediaPropertyPredicate predicateWithValue:musicIdentifier forProperty:MPMediaItemPropertyPersistentID]]];
MPMediaItem *item = query.items.firstObject;
There are multiple memory leaks in this section of my code. Specifically with these arrays: PlaylistItem, PlaylistItemID and PlaylistItemLength. The problem is that I can't successfully release the arrays. When I attempt to use insert [xxxx release]; anywhere in this code, the app locks up. It's driving me absolutely nurtz!
-(void)configureCueSet {
MPMediaQuery *myPlaylistsQuery = [MPMediaQuery playlistsQuery];
NSArray *playlists = [myPlaylistsQuery collections];
//Get # of items in a playlist and names -------------------------------------
NSArray *songs;
for (MPMediaPlaylist *playlist in playlists) {
NSString *playListItem = [playlist valueForProperty: MPMediaPlaylistPropertyName];
if ([playListItem isEqualToString: savedLastSelectedPlaylist]){
songs = [playlist items];
}
}
PlaylistItem = [[NSMutableArray alloc] init];
PlaylistItemID = [[NSMutableArray alloc] init];
PlaylistItemLength = [[NSMutableArray alloc] init];
for (MPMediaItem *song in songs) {
[PlaylistItem addObject:[song valueForProperty: MPMediaItemPropertyTitle]];
[PlaylistItemID addObject:[song valueForProperty: MPMediaItemPropertyPersistentID]];
[PlaylistItemLength addObject:[song valueForProperty: MPMediaItemPropertyPlaybackDuration]];
}
}
Does that method get called multiple times? If so, your leak likely occurs on that assignment. You'd want:
[PlayListItem release];
PlaylistItem = [[NSMutableArray alloc] init];
[PlayListItemID release];
PlaylistItemID = [[NSMutableArray alloc] init];
[PlaylistItemLength release];
PlaylistItemLength = [[NSMutableArray alloc] init];
If you don't release what was there before, then you'll get a leak.
Attempting to insert [xxx release] would release the contents, not the arrays. The application crashes because with that you are deallocating the object which you are about to add to the array. According to the documentation (here), the values in an NSArray are automatically retained, and will be released as soon as the array is dealloc'ed. So, if you want to release any of those arrays, simply type [PlaylistItem release].