如何获取 iPhone 中音频文件的详细信息

发布于 2024-12-17 16:39:05 字数 209 浏览 0 评论 0原文

我使用 AVAudioPlayer 制作了自定义播放器。现在,我想获取添加在资源文件夹中的音频文件的详细信息,例如艺术家姓名、专辑名称等。

MPMusicPlayer 提供了用于获取详细信息的 API,但它使用 iPod 库并且不从应用程序的沙箱中获取资源。因此,MPMusicPlayer 在这种情况下不起作用。

那么,我们如何获取iPhone中音频文件的详细信息呢?

I made the custom player by using AVAudioPlayer. Now, I want to fetch the details of the audio file such as artist name,album name,etc which is added in the resource folder.

MPMusicPlayer provides the API for fetching the details but its using iPod library and its not taking the resource from sandbox of application. So, MPMusicPlayer is not going to work in that scenario.

So, how can we fetch the details of audio file in iPhone.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三人与歌 2024-12-24 16:39:05

您可以通过 AudioToolbox.framework 获取此信息。 AudioToolbox.framework 是一个 C API,所以我为它编写了一个 Objective-C 包装器:

ID3Tag .h:

@interface ID3Tag : NSObject <NSCoding> {
    NSString* title_;
    NSString* album_;
    NSString* artist_;
    NSNumber* trackNumber_;
    NSNumber* totalTracks_;
    NSString* genre_;
    NSString* year_;
    NSNumber* approxDuration_;
    NSString* composer_;
    NSString* tempo_;
    NSString* keySignature_;
    NSString* timeSignature_;
    NSString* lyricist_;
    NSString* recordedDate_;
    NSString* comments_;
    NSString* copyright_;
    NSString* sourceEncoder_;
    NSString* encodingApplication_;
    NSString* bitRate_;
    NSStream* sourceBitRate_;
    NSString* channelLayout_;
    NSString* isrc_;
    NSString* subtitle_;  
}

@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *album;
@property (nonatomic, retain) NSString *artist;
@property (nonatomic, retain) NSNumber *trackNumber;
@property (nonatomic, retain) NSNumber *totalTracks;
@property (nonatomic, retain) NSString *genre;
@property (nonatomic, retain) NSString *year;
@property (nonatomic, retain) NSNumber *approxDuration;
@property (nonatomic, retain) NSString *composer;
@property (nonatomic, retain) NSString *tempo;
@property (nonatomic, retain) NSString *keySignature;
@property (nonatomic, retain) NSString *timeSignature;
@property (nonatomic, retain) NSString *lyricist;
@property (nonatomic, retain) NSString *recordedDate;
@property (nonatomic, retain) NSString *comments;
@property (nonatomic, retain) NSString *copyright;
@property (nonatomic, retain) NSString *sourceEncoder;
@property (nonatomic, retain) NSString *encodingApplication;
@property (nonatomic, retain) NSString *bitRate;
@property (nonatomic, retain) NSStream *sourceBitRate;
@property (nonatomic, retain) NSString *channelLayout;
@property (nonatomic, retain) NSString *isrc;
@property (nonatomic, retain) NSString *subtitle;

@end

ID3TagParser.h

#import <Foundation/Foundation.h>
#import "ID3Tag.h"

@interface ID3Parser : NSObject {

}

- (ID3Tag*) parseAudioFileForID3Tag:(NSURL*) url;

@end

ID3TagParser.m

#import "ID3Parser.h"
#import <AudioToolbox/AudioToolbox.h>

@implementation ID3Parser

- (ID3Tag*) parseAudioFileForID3Tag:(NSURL*) url {
    if (url == nil) {
        return nil;
    }

    AudioFileID fileID  = nil;
    OSStatus err = noErr;

    err = AudioFileOpenURL( (CFURLRef) url, kAudioFileReadPermission, 0, &fileID );
    if( err != noErr ) {
        NSLog( @"AudioFileOpenURL failed" );
        return nil;
    } else {
        UInt32 id3DataSize = 0;
        char* rawID3Tag = NULL;

        //  Reads in the raw ID3 tag info
        err = AudioFileGetPropertyInfo(fileID, kAudioFilePropertyID3Tag, &id3DataSize, NULL);
        if(err != noErr) {
            return nil;
        }

        //  Allocate the raw tag data
        rawID3Tag = (char *) malloc(id3DataSize);

        if(rawID3Tag == NULL) {
            return nil;
        }

        err = AudioFileGetProperty(fileID, kAudioFilePropertyID3Tag, &id3DataSize, rawID3Tag);
        if(err != noErr) {
            return nil;
        }

        UInt32 id3TagSize = 0;
        UInt32 id3TagSizeLength = 0;
        err = AudioFormatGetProperty(kAudioFormatProperty_ID3TagSize, id3DataSize, rawID3Tag, &id3TagSizeLength, &id3TagSize);

        if(err != noErr) {
            switch(err) {
                case kAudioFormatUnspecifiedError:
                    NSLog(@"err: audio format unspecified error");
                    return nil;
                case kAudioFormatUnsupportedPropertyError:
                    NSLog(@"err: audio format unsupported property error");
                    return nil;
                case kAudioFormatBadPropertySizeError:
                    NSLog(@"err: audio format bad property size error"); 
                    return nil;
                case kAudioFormatBadSpecifierSizeError:
                    NSLog(@"err: audio format bad specifier size error"); 
                    return nil;
                case kAudioFormatUnsupportedDataFormatError:
                    NSLog(@"err: audio format unsupported data format error"); 
                    return nil;
                case kAudioFormatUnknownFormatError:
                    NSLog(@"err: audio format unknown format error");
                    return nil;
                default:
                    NSLog(@"err: some other audio format error"); 
                    return nil;
            }
        }

        CFDictionaryRef piDict = nil;
        UInt32 piDataSize = sizeof(piDict);

        //  Populates a CFDictionary with the ID3 tag properties
        err = AudioFileGetProperty(fileID, kAudioFilePropertyInfoDictionary, &piDataSize, &piDict);
        if(err != noErr) {
            NSLog(@"AudioFileGetProperty failed for property info dictionary");
            return nil;
        }

        //  Toll free bridge the CFDictionary so that we can interact with it via objc
        NSDictionary* nsDict = (NSDictionary*)piDict;

        ID3Tag* tag = [[[ID3Tag alloc] init] autorelease];

        tag.album = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Album]];
        tag.approxDuration = [NSNumber numberWithInt:[[nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ApproximateDurationInSeconds]] intValue]];
        tag.artist = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Artist]];
        tag.bitRate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_NominalBitRate]];
        tag.channelLayout = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ChannelLayout]];
        tag.comments = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Comments]];
        tag.composer = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Composer]];
        tag.copyright = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Copyright]];
        tag.encodingApplication = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_EncodingApplication]];
        tag.genre = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Genre]];
        tag.isrc = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ISRC]];
        tag.keySignature = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_KeySignature]];
        tag.lyricist = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Lyricist]];
        tag.recordedDate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_RecordedDate]];
        tag.sourceBitRate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SourceBitDepth]];
        tag.sourceEncoder = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SourceEncoder]];
        tag.subtitle = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SubTitle]];
        tag.tempo = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Tempo]];
        tag.timeSignature = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_TimeSignature]];
        tag.title = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Title]];
        tag.year = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Year]];

        /*  
         *  We're going to parse tracks differently so that we can perform queries on the data. This means we need to look
         *  for a '/' so that we can seperate out the track from the total tracks on the source compilation (if it's there).
         */
        NSString* tracks = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_TrackNumber]];

        int slashLocation = [tracks rangeOfString:@"/"].location;

        if (slashLocation == NSNotFound) {
            tag.trackNumber = [NSNumber numberWithInt:[tracks intValue]];
        } else {
            tag.trackNumber = [NSNumber numberWithInt:[[tracks substringToIndex:slashLocation] intValue]];
            tag.totalTracks = [NSNumber numberWithInt:[[tracks substringFromIndex:(slashLocation+1 < [tracks length] ? slashLocation+1 : 0 )] intValue]];
        }

        //  ALWAYS CLEAN UP!
        CFRelease(piDict);
        nsDict = nil;
        free(rawID3Tag);

        return tag;
    }
}

@end

You can get this information through the AudioToolbox.framework. The AudioToolbox.framework is a C API, so I wrote an Objective-C wrapper for it:

ID3Tag .h:

@interface ID3Tag : NSObject <NSCoding> {
    NSString* title_;
    NSString* album_;
    NSString* artist_;
    NSNumber* trackNumber_;
    NSNumber* totalTracks_;
    NSString* genre_;
    NSString* year_;
    NSNumber* approxDuration_;
    NSString* composer_;
    NSString* tempo_;
    NSString* keySignature_;
    NSString* timeSignature_;
    NSString* lyricist_;
    NSString* recordedDate_;
    NSString* comments_;
    NSString* copyright_;
    NSString* sourceEncoder_;
    NSString* encodingApplication_;
    NSString* bitRate_;
    NSStream* sourceBitRate_;
    NSString* channelLayout_;
    NSString* isrc_;
    NSString* subtitle_;  
}

@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *album;
@property (nonatomic, retain) NSString *artist;
@property (nonatomic, retain) NSNumber *trackNumber;
@property (nonatomic, retain) NSNumber *totalTracks;
@property (nonatomic, retain) NSString *genre;
@property (nonatomic, retain) NSString *year;
@property (nonatomic, retain) NSNumber *approxDuration;
@property (nonatomic, retain) NSString *composer;
@property (nonatomic, retain) NSString *tempo;
@property (nonatomic, retain) NSString *keySignature;
@property (nonatomic, retain) NSString *timeSignature;
@property (nonatomic, retain) NSString *lyricist;
@property (nonatomic, retain) NSString *recordedDate;
@property (nonatomic, retain) NSString *comments;
@property (nonatomic, retain) NSString *copyright;
@property (nonatomic, retain) NSString *sourceEncoder;
@property (nonatomic, retain) NSString *encodingApplication;
@property (nonatomic, retain) NSString *bitRate;
@property (nonatomic, retain) NSStream *sourceBitRate;
@property (nonatomic, retain) NSString *channelLayout;
@property (nonatomic, retain) NSString *isrc;
@property (nonatomic, retain) NSString *subtitle;

@end

ID3TagParser.h

#import <Foundation/Foundation.h>
#import "ID3Tag.h"

@interface ID3Parser : NSObject {

}

- (ID3Tag*) parseAudioFileForID3Tag:(NSURL*) url;

@end

ID3TagParser.m

#import "ID3Parser.h"
#import <AudioToolbox/AudioToolbox.h>

@implementation ID3Parser

- (ID3Tag*) parseAudioFileForID3Tag:(NSURL*) url {
    if (url == nil) {
        return nil;
    }

    AudioFileID fileID  = nil;
    OSStatus err = noErr;

    err = AudioFileOpenURL( (CFURLRef) url, kAudioFileReadPermission, 0, &fileID );
    if( err != noErr ) {
        NSLog( @"AudioFileOpenURL failed" );
        return nil;
    } else {
        UInt32 id3DataSize = 0;
        char* rawID3Tag = NULL;

        //  Reads in the raw ID3 tag info
        err = AudioFileGetPropertyInfo(fileID, kAudioFilePropertyID3Tag, &id3DataSize, NULL);
        if(err != noErr) {
            return nil;
        }

        //  Allocate the raw tag data
        rawID3Tag = (char *) malloc(id3DataSize);

        if(rawID3Tag == NULL) {
            return nil;
        }

        err = AudioFileGetProperty(fileID, kAudioFilePropertyID3Tag, &id3DataSize, rawID3Tag);
        if(err != noErr) {
            return nil;
        }

        UInt32 id3TagSize = 0;
        UInt32 id3TagSizeLength = 0;
        err = AudioFormatGetProperty(kAudioFormatProperty_ID3TagSize, id3DataSize, rawID3Tag, &id3TagSizeLength, &id3TagSize);

        if(err != noErr) {
            switch(err) {
                case kAudioFormatUnspecifiedError:
                    NSLog(@"err: audio format unspecified error");
                    return nil;
                case kAudioFormatUnsupportedPropertyError:
                    NSLog(@"err: audio format unsupported property error");
                    return nil;
                case kAudioFormatBadPropertySizeError:
                    NSLog(@"err: audio format bad property size error"); 
                    return nil;
                case kAudioFormatBadSpecifierSizeError:
                    NSLog(@"err: audio format bad specifier size error"); 
                    return nil;
                case kAudioFormatUnsupportedDataFormatError:
                    NSLog(@"err: audio format unsupported data format error"); 
                    return nil;
                case kAudioFormatUnknownFormatError:
                    NSLog(@"err: audio format unknown format error");
                    return nil;
                default:
                    NSLog(@"err: some other audio format error"); 
                    return nil;
            }
        }

        CFDictionaryRef piDict = nil;
        UInt32 piDataSize = sizeof(piDict);

        //  Populates a CFDictionary with the ID3 tag properties
        err = AudioFileGetProperty(fileID, kAudioFilePropertyInfoDictionary, &piDataSize, &piDict);
        if(err != noErr) {
            NSLog(@"AudioFileGetProperty failed for property info dictionary");
            return nil;
        }

        //  Toll free bridge the CFDictionary so that we can interact with it via objc
        NSDictionary* nsDict = (NSDictionary*)piDict;

        ID3Tag* tag = [[[ID3Tag alloc] init] autorelease];

        tag.album = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Album]];
        tag.approxDuration = [NSNumber numberWithInt:[[nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ApproximateDurationInSeconds]] intValue]];
        tag.artist = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Artist]];
        tag.bitRate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_NominalBitRate]];
        tag.channelLayout = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ChannelLayout]];
        tag.comments = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Comments]];
        tag.composer = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Composer]];
        tag.copyright = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Copyright]];
        tag.encodingApplication = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_EncodingApplication]];
        tag.genre = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Genre]];
        tag.isrc = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ISRC]];
        tag.keySignature = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_KeySignature]];
        tag.lyricist = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Lyricist]];
        tag.recordedDate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_RecordedDate]];
        tag.sourceBitRate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SourceBitDepth]];
        tag.sourceEncoder = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SourceEncoder]];
        tag.subtitle = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SubTitle]];
        tag.tempo = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Tempo]];
        tag.timeSignature = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_TimeSignature]];
        tag.title = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Title]];
        tag.year = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Year]];

        /*  
         *  We're going to parse tracks differently so that we can perform queries on the data. This means we need to look
         *  for a '/' so that we can seperate out the track from the total tracks on the source compilation (if it's there).
         */
        NSString* tracks = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_TrackNumber]];

        int slashLocation = [tracks rangeOfString:@"/"].location;

        if (slashLocation == NSNotFound) {
            tag.trackNumber = [NSNumber numberWithInt:[tracks intValue]];
        } else {
            tag.trackNumber = [NSNumber numberWithInt:[[tracks substringToIndex:slashLocation] intValue]];
            tag.totalTracks = [NSNumber numberWithInt:[[tracks substringFromIndex:(slashLocation+1 < [tracks length] ? slashLocation+1 : 0 )] intValue]];
        }

        //  ALWAYS CLEAN UP!
        CFRelease(piDict);
        nsDict = nil;
        free(rawID3Tag);

        return tag;
    }
}

@end
江湖正好 2024-12-24 16:39:05

我看到标签读取代码 韦恩帖子被复制粘贴得太多了。
如果您使用kAudioFilePropertyInfoDictionary,则不需要id3DataSize,不需要读取原始ID3Tag数据,并且也不会使用id3TagSizeLength id3TagSize。只需打开文件并读取标签即可:

- (NSDictionary *)id3TagsForURL:(NSURL *)resourceUrl
{
    AudioFileID fileID;
    OSStatus result = AudioFileOpenURL((CFURLRef)resourceUrl, kAudioFileReadPermission, 0, &fileID);

    if (result != noErr) {
        NSLog(@"Error reading tags: %li", result);
        return nil;
    }

    CFDictionaryRef piDict = nil;
    UInt32 piDataSize = sizeof(piDict);

    result = AudioFileGetProperty(fileID, kAudioFilePropertyInfoDictionary, &piDataSize, &piDict);
    if (result != noErr)
        NSLog(@"Error reading tags. AudioFileGetProperty failed");

    AudioFileClose(fileID);

    NSDictionary *tagsDictionary = [NSDictionary dictionaryWithDictionary:(NSDictionary*)piDict];
    CFRelease(piDict);

    return tagsDictionary;
}

字典键在 AudioFile.h 中定义,以 kAFInfoDictionary 开头。

然而,还有另一个标签读取键,它会返回不同的结果(与其他键):

- (NSDictionary *)id3TagsForURL:(NSURL *)resourceUrl
{
    AudioFileID fileID;
    OSStatus result = AudioFileOpenURL((CFURLRef)resourceUrl, kAudioFileReadPermission, 0, &fileID);

    if (result != noErr) {
        return nil;
    }

    //read raw ID3Tag size
    UInt32 id3DataSize = 0;
    char *rawID3Tag = NULL;
    result = AudioFileGetPropertyInfo(fileID, kAudioFilePropertyID3Tag, &id3DataSize, NULL);
    if (result != noErr) {
        AudioFileClose(fileID);
        return nil;
    }

    rawID3Tag = (char *)malloc(id3DataSize);

    //read raw ID3Tag
    result = AudioFileGetProperty(fileID, kAudioFilePropertyID3Tag, &id3DataSize, rawID3Tag);
    if (result != noErr) {
        free(rawID3Tag);
        AudioFileClose(fileID);
        return nil;
    }

    CFDictionaryRef piDict = nil;
    UInt32 piDataSize = sizeof(piDict);

    //this key returns some other dictionary, which works also in iPod library
    result = AudioFormatGetProperty(kAudioFormatProperty_ID3TagToDictionary, id3DataSize, rawID3Tag, &piDataSize, &piDict);
    if (result != noErr) {
        return nil;
    }

    free(rawID3Tag);
    AudioFileClose(fileID);

    NSDictionary *tagsDictionary = [NSDictionary dictionaryWithDictionary:(NSDictionary*)piDict];
    CFRelease(piDict);

    return tagsDictionary;
}

I see that the tag-reading code Wayne posts is being copy-pasted too much.
If you use kAudioFilePropertyInfoDictionary, you don't need id3DataSize, don't need to read raw ID3Tag data and id3TagSizeLength id3TagSize are not used also. Just open the file and read the tag:

- (NSDictionary *)id3TagsForURL:(NSURL *)resourceUrl
{
    AudioFileID fileID;
    OSStatus result = AudioFileOpenURL((CFURLRef)resourceUrl, kAudioFileReadPermission, 0, &fileID);

    if (result != noErr) {
        NSLog(@"Error reading tags: %li", result);
        return nil;
    }

    CFDictionaryRef piDict = nil;
    UInt32 piDataSize = sizeof(piDict);

    result = AudioFileGetProperty(fileID, kAudioFilePropertyInfoDictionary, &piDataSize, &piDict);
    if (result != noErr)
        NSLog(@"Error reading tags. AudioFileGetProperty failed");

    AudioFileClose(fileID);

    NSDictionary *tagsDictionary = [NSDictionary dictionaryWithDictionary:(NSDictionary*)piDict];
    CFRelease(piDict);

    return tagsDictionary;
}

Dicionary keys are defined in AudioFile.h, starting with kAFInfoDictionary.

However, there is another tag-reading key, which will return different results (with other keys):

- (NSDictionary *)id3TagsForURL:(NSURL *)resourceUrl
{
    AudioFileID fileID;
    OSStatus result = AudioFileOpenURL((CFURLRef)resourceUrl, kAudioFileReadPermission, 0, &fileID);

    if (result != noErr) {
        return nil;
    }

    //read raw ID3Tag size
    UInt32 id3DataSize = 0;
    char *rawID3Tag = NULL;
    result = AudioFileGetPropertyInfo(fileID, kAudioFilePropertyID3Tag, &id3DataSize, NULL);
    if (result != noErr) {
        AudioFileClose(fileID);
        return nil;
    }

    rawID3Tag = (char *)malloc(id3DataSize);

    //read raw ID3Tag
    result = AudioFileGetProperty(fileID, kAudioFilePropertyID3Tag, &id3DataSize, rawID3Tag);
    if (result != noErr) {
        free(rawID3Tag);
        AudioFileClose(fileID);
        return nil;
    }

    CFDictionaryRef piDict = nil;
    UInt32 piDataSize = sizeof(piDict);

    //this key returns some other dictionary, which works also in iPod library
    result = AudioFormatGetProperty(kAudioFormatProperty_ID3TagToDictionary, id3DataSize, rawID3Tag, &piDataSize, &piDict);
    if (result != noErr) {
        return nil;
    }

    free(rawID3Tag);
    AudioFileClose(fileID);

    NSDictionary *tagsDictionary = [NSDictionary dictionaryWithDictionary:(NSDictionary*)piDict];
    CFRelease(piDict);

    return tagsDictionary;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文