新手问题,
我有3个Class,其中3个是来自NSOBject的子类。
集合类,有2个属性, masterSong为NSMutableSet (强,非原子)和 listOfPlaylists为NSMutableArray (强,非原子) )
播放列表
有2个属性, playListName为NSString (copy,nonatomic), songList为NSMutableArray (强,非原子)
3。 歌曲课程
拥有4个属性:标题,艺术家,专辑,游戏时间为NSString(复制,非原子)。
masterSong将包含Song对象,listOfPlaylist将包含播放列表对象。
而songList仅存储对Song对象的引用。
我想通过在masterSong中查找标题,艺术家或专辑的歌曲来为Collection Class创建removeSong方法。
如果查找找到1,它将返回NSSet,返回的NSSet将作为参数在minusSet:方法中从masterSong和所有Playlist.songList中删除。
但是,我无法弄清楚如何写下NSPredicate语法来过滤掉包含Song Object的masterSong中的.title或.album或.artist。
这是我到目前为止所得到的 Collection.m
- (void) removeSong: (NSString *)zSong{
//remove from reference playlist
NSSet *targets = [self lookUpTitle:zSong];
if ([targets count]>0) {
[self.masterSongs minusSet:targets];
for (Playlist *playlist in listOfPlaylists) {
// -all objects converts the set into array.
[playlist.songList removeObjectsInArray:[targets allObjects]];
}
}
else
;
}
执行lookUpTitle方法时Xcode抛出异常,因为由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'无法查找值(标题:不返回的整点,艺术家:Cafe Bleu,专辑:CBSB,游戏时间:3:56)字符串(你知道什么);值不是字符串
- (NSSet *) lookUpTitle: (NSString *)aName {
NSString *filters = @"%K CONTAINS [cd] %@";
NSPredicate *filter = [NSPredicate predicateWithFormat:filters, @"title", aName];
NSSet *result = [masterSongs filteredSetUsingPredicate:filter];
if ([result count] == 0) {
NSLog(@"not found");
return nil;
}
else{
return result;
}
}
我知道主要问题是在lookUpTitle方法
NSPredicate *filter = [NSPredicate predicateWithFormat:filters, @"title", aName];
NSSet *result = [masterSongs filteredSetUsingPredicate:filter];
过滤器以错误的方式过滤,而它应该过滤NSString对象(标题,艺术家或专辑),但是masterSong包含Song对象,如何使用NSPredicate访问放置在masterSong内的Song对象中的标题,艺术家,专辑?
这种情况的其他任何有效方法吗?
Predicate Programming Guide仅显示包含字符串
的示例集/数组我找到了其他帖子which has similar topic,但是块读取起来很困惑,但在我的情况下仍然无效。
编辑按响应者#1的要求添加部分代码(Class.m方法)。 这里是与我的问题相关的.m文件中的一些方法
的main.m
#import <Foundation/Foundation.h>
#import "MusicCollection.h"
#import "Playlist.h"
#import "Song.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
// insert code here...
// NSLog(@"Hello, World!");
//create Songs
Song *aSong = [[Song alloc]initWithTitle:@"Whole point of no return" withArtist:@"Cafe Bleu" withAlbum:@"CBSB" withPlaytime:@"3:56"];
Song *bSong = [[Song alloc]initWithTitle:@"Council Meetin'" withArtist:@"Cafe Bleu" withAlbum:@"CBSB" withPlaytime:@"4:00"];
Song *cSong = [[Song alloc]initWithTitle:@"Hayate" withArtist:@"Spitz" withAlbum:@"Indigo Chiheisen" withPlaytime:@"4:21"];
Song *dSong = [[Song alloc]initWithTitle:@"I have a Dreams" withArtist:@"WestLife" withAlbum:@"Season" withPlaytime:@"4:11"];
Song *eSong = [[Song alloc]initWithTitle:@"What Do You Know" withArtist:@"David Choi" withAlbum:@"Tomorrow" withPlaytime:@"3:46"];
//create playList
Playlist *playlistA = [[Playlist alloc]initWithName:@"Playlist A"];
Playlist *playListB = [[Playlist alloc]initWithName:@"Playlist B"];
//store Song A & B to Playlist A and Song A,B,C to playlist B
[playlistA addSong:aSong];
[playlistA addSong:bSong];
[playListB addSong:aSong];
[playListB addSong:bSong];
[playListB addSong:cSong];
// [playListB removeSong:eSong];
//Creating Master Collection
MusicCollection *myCollection = [[MusicCollection alloc]initWithName:@"Library"];
[myCollection addPlaylist:playlistA];
[myCollection addPlaylist:playListB];
[myCollection addSong:eSong];
[myCollection addSong:dSong];
[myCollection removePlaylist:playListB];
[myCollection removeSong:aSong];
NSSet *container2 = [myCollection lookUpTitle:@"What"];
NSLog(@"%@",container2);
// NSLog(@"%@",myCollection);
}
return 0;
}
Collection.m
-(instancetype) initWithName: (NSString *)aName{
self = [super init];
if (self) {
self.name = [NSMutableString stringWithString:aName];
self.listOfPlaylists = [NSMutableArray array];
self.masterSongs = [NSMutableSet set];
}
return self;
}
-(instancetype) init{
return [self initWithName:@""];
}
-(void) addPlaylist: (Playlist *)aPlayList{
if ([listOfPlaylists containsObject:aPlayList]==YES) {
}
else
[listOfPlaylists addObject:aPlayList];
}
-(void) removePlaylist: (Playlist *)aPlayList{
if ([listOfPlaylists containsObject:aPlayList]) {
[listOfPlaylists removeObjectIdenticalTo:aPlayList];
}
else{
;
}
}
- (void) displaySong{
NSLog(@"displaying all song in Collection");
NSLog(@" %@",self.masterSongs);
}
- (void) addSong :(Song *)aSong{
if (![masterSongs containsObject:aSong]) {
[masterSongs addObject:aSong];
}
}
- (void) removeSong: (NSString *)zSong{
//remove from reference playlist
NSSet *targets = [self lookUpTitle:zSong];
if ([targets count]>0) {
[self.masterSongs minusSet:targets];
for (Playlist *playlist in listOfPlaylists) {
// -all objects converts the set into array.
[playlist.songList removeObjectsInArray:[targets allObjects]];
}
}
else
;
}
- (NSSet *) lookUpTitle: (NSString *)aName {
NSString *filters = @"%K CONTAINS [cd] %@";
NSPredicate *filter = [NSPredicate predicateWithFormat:filters, @"title", aName];
NSSet *result = [masterSongs filteredSetUsingPredicate:filter];
if ([result count] == 0) {
NSLog(@"not found");
return nil;
}
else{
return result;
}
}
Playlist.m
- (void) addSong :(Song *)aSong{
if (![songList containsObject:aSong]) {
[songList addObject:aSong];
}
}
- (void) removeSong: (Song *)aSong{
if ([songList containsObject:aSong]){
[self.songList removeObjectIdenticalTo:aSong];
}
}
- (instancetype) initWithName: (NSString *)aPLName{
self = [super init];
if (self) {
self.songList = [NSMutableArray array];
self.playlistName = aPLName;
}
return self;
}
- (instancetype)init{
return [self initWithName:@""];
}
Song.m
- (instancetype) initWithTitle: (NSString *)aTitle withArtist: (NSString *)anArtist withAlbum: (NSString *)aAlbum withPlaytime: (NSString *)playingTime{
self = [super init];
if (self) {
self.artist = [NSMutableString stringWithString:anArtist];
self.album = [NSMutableString stringWithString:aAlbum];
self.title = [NSMutableString stringWithString:aTitle];
self.playtime = [NSMutableString stringWithString:playingTime];
}
return self;
}
-(instancetype) init{
return [self initWithTitle:@"null" withArtist:@"null" withAlbum:@"null" withPlaytime:@"null"];
}
答案 0 :(得分:2)
您不需要使用-predicateWithBlock
,在您的情况下使用以下谓词就足够了
[NSPredicate predicateWithFormat:@"SELF.title CONTAINS %@", @"Layla"];
修改强>
Jeffery Thomas是对的,问题出在这一行 - 实际上编译器会发出警告
[myCollection removeSong:aSong];
你要传递给-removeSong:
一个歌曲对象,而不是歌曲的标题。如果您要传递给-removeSong:
,Song
对象会将方法签名从- (void)removeSong:(NSString *)songTitle
更改为-(void)removeSong:(Song*)song
,并相应地更改方法实现,以将该歌曲的标题传递给谓词一个NSString
- (void) removeSong: (Song *)zSong {
//remove from reference playlist
NSSet *targets = [self lookUpTitle:zSong.title];
if ([targets count]>0) {
[self.masterSongs minusSet:targets];
for (Playlist *playlist in self.listOfPlaylists) {
// -all objects converts the set into array.
[playlist.songList removeObjectsInArray:[targets allObjects]];
}
}
}
从现在开始,请不要忽略编译器警告,以免过去几天调试这种微妙的错误。
答案 1 :(得分:2)
你重载了-removeSong:
的含义,这让你感到困惑。在Playlist
中,-removeSong:
获取了Song
个实例,但在Collection
中,-removeSong:
为歌曲标题提供了NSString
个实例。
问题是您将Song
的实例传递给期望NSString
的版本。
- (void)removeSong:(NSString *)zSong
{
NSSet *targets = [self lookUpTitle:zSong];
// …
}
应该是
- (void)removeSong:(Song *)aSong
{
NSSet *targets = [self lookUpTitle:aSong.title];
// …
}
或
- (void)removeSongWithTitle:(NSString *)aTitle
{
NSSet *targets = [self lookUpTitle:aTitle];
// …
}
我更改了方法的第二个版本的名称,以清楚地显示预期参数是什么。如果要使用第二个版本,可以传递消息[myCollection removeSongWithTitle:aSong.title]