NSData, NSValue, NSKeyedArchiver and non objects

# Objective-C

做的一个Framework跟App整合到一起,因为用到了多线程,所以通信不可避免,但是Framework里又载入了一个C++的Plugin,里面有许多struct,在把这类struct变成对象序列化时遇到问题。
以前做的很傻,把struct的所有成员用NSDictionary来一个个封装,再一个个反序列化,好傻呀。要是struct定义变了,那代码就又要修改了~所以重构了一下,这里给出怎样对non object数据结构进行对象封装和序列化。

怎样进行封装是引用JongAm‘s一篇博文。
原文地址:http://jongampark.wordpress.com/2008/08/07/nsvalue-and-non-object-types/


当你想使用Cocoa的集合来存储非对象型数据时,NSValue和NSNumber是非常有用的。NSNumber是NSValue的子类,所以NSValue更灵活一些。
我们先看看NSValue能做什么:

所以下面的代码是可行的:

==========================================================================
==========================================================================

一个NSValue对象是用来存储一个C或者Objective-C数据的简单容器。它可以保存任意类型的数据,比如int,float,char,当然也可以是指pointers, structures, and object ids。NSValue类的目标就是允许以上数据类型的数据结构能够被添加到集合里,例如那些需要其元素是对象的数据结构,如NSArray或者NSSet的实例。需要注意的是NSValue对象一直是不可枚举的。


  // assume ImaginaryNumber defined:
  typedef struct {
  float real;
  float imaginary;
  } ImaginaryNumber;
 
  ImaginaryNumber miNumber;
  miNumber.real = 1.1;
  miNumber.imaginary = 1.41;
 
  NSValue *miValue = [NSValue value:miNumber
  withObjCType:@encode(ImaginaryNumber)]; // encode using the type name
 
  ImaginaryNumber miNumber2;
[miValue getValue:&miNumber2];

==========================================================================
==========================================================================

是不是影像很深刻呢?然而不管怎样,苹果的文档里有一行看起来有点含混的解释:

时刻记住你的struct类型必须是定长的。你不可以存储C字符串,不定长数组和结构和其他的一些不定长的数据类型到NSValue中去。你应该使用NSString或者NSData来存储此类不定长数据。当然你可以把一个指向变长对象的指针存储在NSValue对象中。

这是什么意思呢?如果你的数据不是定长的会发生什么?它能被正确的存储下来吗?

==========================================================================
==========================================================================

  typedef struct {
  int dataSize;
  char *data;
  int year;
  } myStructType1;


==========================================================================
==========================================================================

当data指向一个字符数组时,它能被正确的编码吗?
回答是很简单的,它是变长的,所以它指向的数据不会被编码。
只有这个指针地址被编码了。所以,如果你有一个服务线程编码了一个myStructTyle1的数据发布出去,并释放了这快内存,那么客户线程拿到这个数据解码并试图获取data的原始数据时,那就只能得到data的指针地址,而不是数据内容。所以不要期望它能存储你的data。你应该使用NSData或者NSArchiver来代替NSValue以达到期望目标。

如:

  typedef struct {
  int age;
  int month;
  int day;
  } innerType;
 
  typedef struct {
  int dataSize;
  innerType *innerData;
  } myStructType2;

==========================================================================
==========================================================================

恩,innerTyle是一个定长的类型变量,那么它会被正确编码吗?
不会,苹果的文档并没有说明此类情况。它依然只编码指针而不是内容。
所以在这种情况下,依然得使用NSData。
总结,使用NSValue只能是对那些没有变量是指针的struct。
Then how the NSValue stores? It is kind of shallow copy. Please read this.
Here the address of myCString is passed (&myCString), so the address of the first character of the string is stored in theValue. Note that the NSValue object doesn’t copy the contents of the string, but the pointer itself. If you create an NSValue object with an allocated data item, don’t deallocate its memory while the NSValue object exists.

**************************************************************************************

不管是NSValue还是NSData,都是可以对非对象进行编码存储的。但在我的工程里,线程之间通信的数据是需要进行序列化的,我使用了NSKeyedArchiver来序列化。
在使用过程中发现NSValue存储的数据不可被序列化,而NSData可以。我的struct是定长的。

所以最好包装时都使用NSData吧,如果时rect, point之类的倒是可以用NSvalue,它已经提供好接口供你使用了。





实例:2:使用NSOperation和NSOperationQueue启动多线程

在app store中的很多应用程序非常的笨重,他们有好的界面,但操作性很差,比如说当程序从网上或本地载入数据的时候,界面被冻结了,用户只能等程序完全载入数据之后才能进行操作。
当打开一个应用程序时,iphone会产生一个包含main方法的线程,所用程序中的界面都是运行在这个线程之中的(table views, tab bars, alerts…),有时候我们会用数据填充这些view,现在问 题是如何有效的载入数据,并且用户还能自如的操作程序。方法是启动新的线程,专门用于数据的下载,而主线程不会因为下载数据被阻塞。
不管使用任何编程语言,在实现多线程时都是一件很麻烦的事情。更糟糕的是,一旦出错,这种错误通常相当糟糕。然而,幸运的是apple从os x10.5在这方面做了很多的改进,NSThread的引入,使得开发多线程应用程序容易多了。除此之外,它们还引入了两个全新的类,NSOperation和NSOperationQueue。
接下来我们通过一个实例来剖析如何使用这两个类实现多线程。这里指示展示这两个类的基本用法,当然这不是使用他们的唯一办法。
如果你熟悉java或者它的别的变种语言的话 ,你会发现NSOperation对象很像java.lang.Runnable接口,就像java.lang.Runnable接口那样,NSOperation类也被设计为可扩展的,而且只有一个需要重写的方法。它就是-(void)main。使用NSOperation的最简单的方式就是把一个NSOperation对象加入到NSOperationQueue队列中,一旦这个对象被加入到队列,队列就开始处理这个对象,直到这个对象的所有操作完成。然后它被队列释放。
下面的例子中,使用一个获取网页,并对其解析程NSXMLDocument,最后将解析得到的NSXMLDocument返回给主线程。

==========================================================================
==========================================================================

PageLoadOperation.h@interface PageLoadOperation : NSOperation {
    NSURL *targetURL;}
@property(retain) NSURL *targetURL;
- (id)initWithURL:(NSURL*)url;@end

PageLoadOperation.m
#import "PageLoadOperation.h"#import "AppDelegate.h"@implementation PageLoadOperation@synthesize targetURL;- (id)initWithURL:(NSURL*)url;{
    if (![super init]) return nil;
    [self setTargetURL:url];
    return self;}- (void)dealloc {
    [targetURL release], targetURL = nil;
    [super dealloc];
}
- (void)main
{
    NSString *webpageString = [[NSString alloc]
    initWithContentsOfURL:[self targetURL] autorelease];
    NSError *error = nil;
    NSXMLDocument *document = [NSXMLDocument alloc]
    initWithXMLString:webpageString
    options:NSXMLDocumentTidyHTML error:&error];
    if (!document) {
        NSLog(@"%s Error loading document (%@): %@",
        _cmd, [self targetURL] absoluteString], error);
         return;
    }
    [AppDelegate shared]
    performSelectorOnMainThread:@selector(pageLoaded:)
         withObject:document waitUntilDone:YES];
    [document release];
}
@end

==========================================================================
==========================================================================

正如我们所看到的那样,这个类相当的简单,在它的init方法中接受一个url并保存起来,当main函数被调用的时候,它使用这个保存的url创建一个字符串,并将这个字符串传递给NSXMLDocumentinit方法。如果加载的xml数据没有出错,数据会被传递给AppDelegate,它处于主线程中。到此,这个线程的任务就完成了。在主线程中注销操作队列的时候,会将这个NSOperation对象释放。

AppDelegate.h
@interface AppDelegate : NSObject {
    NSOperationQueue *queue;
}+ (id)shared;- (void)pageLoaded:(NSXMLDocument*)document;@endAppDelegate.m #import "AppDelegate.h"#import "PageLoadOperation.h"@implementation AppDelegate
static AppDelegate *shared;
static NSArray *urlArray;
- (id)init
{
    if (shared)
    {
        [self autorelease];
        return shared;
    }
    if (![super init]) return nil; NSMutableArray *array = [NSMutableArray alloc] init];[array addObject:@"http://www.google.com"];[array addObject:@"http://www.apple.com"];[array addObject:@"http://www.yahoo.com"];[array addObject:@"http://www.zarrastudios.com"];[array addObject:@"http://www.macosxhints.com"];urlArray = array; queue = [NSOperationQueue alloc] init];shared = self;return self;
    }
    • (void)applicationDidFinishLaunching:
    (NSNotification *)aNotification
{
        for (NSString *urlString in urlArray)
        {
        NSURL *url =
        [NSURL URLWithString:urlString]; PageLoadOperation *plo =
        [PageLoadOperation alloc] initWithURL:url];
        [queue addOperation:plo];
        [plo release];
        }
}
- (void)dealloc
{
        [queue release], queue = nil;
        [super dealloc];
}
+ (id)shared;
{
        if (!shared) {
            [AppDelegate alloc] init];
        }
        return shared;
}
- (void)pageLoaded:(NSXMLDocument*)document;
{
        NSLog(@"%s Do something with the XMLDocument: %@",
             _cmd, document);
}
@end

==========================================================================
==========================================================================

NSOperationQueue的并行控制(NSOperationQueue Concurrency)
        在上面这个简单的例子中,我们很难看出这些操作是并行运行的,然而,如果你你的操作花费的时间远远比这里的要长,你将会发现,队列是同时执行这些操作的。幸运的是,如果你想要为队列限制同时只能运行几个操作,你可以使用NSOperationQueue的setMaxConcurrentOperationCount:方法。

例如,[queue setMaxConcurrentOperationCount:2];




==========================================================================
====================================================================================================================================================
==========================================================================

工程起始:

    1. 添加源文件和framework
    
    开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息。如果没有处理它们,是不会通过Apple的审(我们的)查的。
    Apple 的 例程 Reachability 中介绍了取得/检测网络状态的方法。要在应用程序程序中使用Reachability,首先要完成如下两部:
    
    1.1. 添加源文件:
    在你的程序中使用 Reachability 只须将该例程中的 Reachability.h 和 Reachability.m 拷贝到你的工程中。如下图:

    
    
    1.2.添加framework:
    将SystemConfiguration.framework 添加进工程。如下图:
    
    
    2. 网络状态

==========================================================================
   
    Reachability.h中定义了三种网络状态:
    typedef enum {
        NotReachable = 0, //无连接
        ReachableViaWiFi, //使用3G/GPRS网络
        ReachableViaWWAN //使用WiFi网络
    } NetworkStatus;
    
==========================================================================

    因此可以这样检查网络状态:
==========================================================================

    Reachability *r = [Reachability reachabilityWithHostName:@“www.apple.com”];
    switch ([r currentReachabilityStatus]) {
            case NotReachable:
                    // 没有网络连接
                    break;
            case ReachableViaWWAN:
                    // 使用3G网络
                    break;
            case ReachableViaWiFi:
                    // 使用WiFi网络
                    break;
    }
 ==========================================================================
    3.检查当前网络环境
    程序启动时,如果想检测可用的网络环境,可以像这样

==========================================================================
    // 是否wifi
    + (BOOL) IsEnableWIFI {
        return ([Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable);
    }

    // 是否3G
    + (BOOL) IsEnable3G {
        return ([Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable);
    }


    例子:
    - (void)viewWillAppear:(BOOL)animated {
    if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) &&
            ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) {
            self.navigationItem.hidesBackButton = YES;
            [self.navigationItem setLeftBarButtonItem:nil animated:NO];
        }
    }
==========================================================================

    4. 链接状态的实时通知
    网络连接状态的实时检查,通知在网络应用中也是十分必要的。接续状态发生变化时,需要及时地通知用户:

==========================================================================
    Reachability 1.5版本
    // My.AppDelegate.h
    #import "Reachability.h"

    @interface MyAppDelegate : NSObject <UIApplicationDelegate> {
        NetworkStatus remoteHostStatus;
    }

    @property NetworkStatus remoteHostStatus;

    @end

    // My.AppDelegate.m
    #import "MyAppDelegate.h"

    @implementation MyAppDelegate
    @synthesize remoteHostStatus;

    // 更新网络状态
    - (void)updateStatus {
        self.remoteHostStatus = [Reachability sharedReachability] remoteHostStatus];
    }

    // 通知网络状态
    - (void)reachabilityChanged:(NSNotification *)note {
        [self updateStatus];
        if (self.remoteHostStatus == NotReachable) {
            UIAlertView *alert = [UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil)
                         message:NSLocalizedString (@"NotReachable", nil)
                        delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
            [alert show];
            [alert release];
        }
    }

    // 程序启动器,启动网络监视
    - (void)applicationDidFinishLaunching:(UIApplication *)application {
    
        // 设置网络检测的站点
        [Reachability sharedReachability] setHostName:@"www.apple.com"];
        [Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES];
        // 设置网络状态变化时的通知函数
        [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:)
                                                 name:@"kNetworkReachabilityChangedNotification" object:nil];
        [self updateStatus];
    }

    - (void)dealloc {
        // 删除通知对象
        [NSNotificationCenter defaultCenter] removeObserver:self];
        [window release];
        [super dealloc];
    }
    
    Reachability 2.0版本
    

    // MyAppDelegate.h
    @class Reachability;

        @interface MyAppDelegate : NSObject <UIApplicationDelegate> {
            Reachability *hostReach;
        }

    @end

    // MyAppDelegate.m
    - (void)reachabilityChanged:(NSNotification *)note {
        Reachability* curReach = [note object];
        NSParameterAssert([curReach isKindOfClass: [Reachability class]);
        NetworkStatus status = [curReach currentReachabilityStatus];
    
        if (status == NotReachable) {
            UIAlertView *alert = [UIAlertView alloc] initWithTitle:@"AppName""
                              message:@"NotReachable"
                              delegate:nil
                              cancelButtonTitle:@"YES" otherButtonTitles:nil];
                              [alert show];
                              [alert release];
        }
    }
                              
    - (void)applicationDidFinishLaunching:(UIApplication *)application {
        // ...
                  
        // 监测网络情况
        [NSNotificationCenter defaultCenter] addObserver:self
                              selector:@selector(reachabilityChanged:)
                              name: kReachabilityChangedNotification
                              object: nil];
        hostReach = [Reachability reachabilityWithHostName:@"www.google.com"] retain];
        hostReach startNotifer];
        // ...
    }

==========================================================================
==========================================================================


二:使用NSConnection下载数据
    
    1.创建NSConnection对象,设置委托对象
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]];
    [NSURLConnection connectionWithRequest:request delegate:self];
    
    2. NSURLConnection delegate委托方法
        - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
        - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
        - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
        - (void)connectionDidFinishLoading:(NSURLConnection *)connection;

    3. 实现委托方法
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
        // store data
        [self.receivedData setLength:0]; //通常在这里先清空接受数据的缓存
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
           /* appends the new data to the received data */
        [self.receivedData appendData:data]; //可能多次收到数据,把新的数据添加在现有数据最后
    }

    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
        // 错误处理
    }

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
        // disconnect
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        NSString *returnString = [NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
        NSLog(returnString);
        [self urlLoaded:[self urlString] data:self.receivedData];
        firstTimeDownloaded = YES;
    }

三:使用NSXMLParser解析xml文件

    1. 设置委托对象,开始解析
    NSXMLParser *parser = [NSXMLParser alloc] initWithData:data]; //或者也可以使用initWithContentsOfURL直接下载文件,但是有一个原因不这么做:
    // It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable
    // because it gives less control over the network, particularly in responding to connection errors.
    [parser setDelegate:self];
    [parser parse];

    2. 常用的委托方法
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
                                namespaceURI:(NSString *)namespaceURI
                                qualifiedName:(NSString *)qName
                                attributes:(NSDictionary *)attributeDict;
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
                                namespaceURI:(NSString *)namespaceURI
                                qualifiedName:(NSString *)qName;
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError;

    static NSString *feedURLString = @"http://www.newegg.com.cn/Product/A26-115-1HW.htm";

    3. 应用举例
    - (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error
    {
        NSXMLParser *parser = [NSXMLParser alloc] initWithContentsOfURL:URL];
        [parser setDelegate:self];
        [parser setShouldProcessNamespaces:NO];
        [parser setShouldReportNamespacePrefixes:NO];
        [parser setShouldResolveExternalEntities:NO];
        [parser parse];
        NSError *parseError = [parser parserError];
        if (parseError && error) {
            *error = parseError;
        }
        [parser release];
    }

    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
                                        qualifiedName:(NSString*)qName attributes:(NSDictionary *)attributeDict{
        // 元素开始句柄
        if (qName) {
            elementName = qName;
        }
        if ([elementName isEqualToString:@"user"]) {
            // 输出属性值
            NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]);
        }
    }

    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
                                        qualifiedName:(NSString *)qName
    {
        // 元素终了句柄
        if (qName) {
               elementName = qName;
        }
    }

    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        // 取得元素的text
    }

    NSError *parseError = nil;
    [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError];




==========================================================================
====================================================================================================================================================
==========================================================================

APP OBJ 实例
/* Function For 百度 mp3 搜索模块 */
/*
请求百度mp3搜索页面获得歌曲信息数组
by BinJian.Wong on Sleeplez.com
update on 2010.2.1
mykeyWords = 关键字
pageNavi = 歌曲条目从pageNavi起
*/
+(NSArray*) KeyWordsForSongs:(NSString*)myKeyWords pageNavi:(int)myPageNavi;
/*
解密百度mp3链接加密算法
by BinJian.Wong on Sleeplez.com
update on 2010.2.1
myEncodeURL = 经过加密的链接
*/
+(NSString*) decodeBaiduURL:(NSString *)myEncodeURL;
/*
从百度下载页面中获得经过加密的下载链接
by BinJian.Wong on Sleeplez.com
update on 2010.2.1
myDownpage = 下载页面的链接地址
*/
+(NSString*) DownPageURLToMusicFileURL:(NSString *)myDownpage;

// .m

[/pre]+(NSArray*) KeyWordsForSongs:(NSString*)myKeyWords pageNavi:(int)myPageNavi{
    int pageNavi = myPageNavi; //页码
    NSString * keyWords = myKeyWords; //关键字
    //NSString * keyWords = @"林肯公园";
    //创建字符串
    NSString * myURL = [NSString stringWithFormat:@"http://mp3.baidu.com/m?f=ms&rf=idx&tn=baidump3&ct=134217728&lf=&rn=&word=%@&lm=0&pn=%d",keyWords,pageNavi];
    //UTF8 to gb2312
    myURL = [myURL stringByAddingPercentEscapesUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)];
    NSLog(@"%@",myURL);
 
    ASIHTTPRequest *myRequest = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:myURL] autorelease];
    [myRequest startSynchronous];
 
 
    //如果发生错误,返回nil
    if ([myRequest error]) return nil;
 
    //返回数组定义
    NSMutableArray * mySongs = [NSMutableArray arrayWithCapacity:15];
 
    //编码转换 gb2313 to UTF
    NSData * myResponseData = [myRequest responseData];
    NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding (kCFStringEncodingGB_18030_2000);
    NSString * myResponseStr = [NSString alloc] initWithData:myResponseData encoding:enc];
 
    //NSLog(@"html=%@",myResponseStr);
 
    //如果百度没有返回结果
    NSRange myRange;
    myRange = [myResponseStr rangeOfString:@"抱歉,没有找到与"];
    if (myRange.location != NSNotFound) {
        return nil;
    };
 
    //将源代码按 ” <td class=d><a href= “ 切割
    NSMutableArray * myResponseArrForSinger = (NSMutableArray *)[myResponseStr componentsSeparatedByString:@"<td class=d><a href="];
    //去头去尾
    if ([myResponseArrForSinger count]>=2) {
        [myResponseArrForSinger removeObjectAtIndex:0];
        [myResponseArrForSinger removeObjectAtIndex:[myResponseArrForSinger count]-1];
    }
 
    //按段处理
    for (int i=0; i<[myResponseArrForSinger count]; i++) {
        //
        @try {
 
            //把段按 “ .html" target="_blank"> ” 切割
            NSMutableArray * mySubArr = (NSMutableArray *)[myResponseArrForSinger objectAtIndex:i] componentsSeparatedByString:@".html\" target=\"_blank\">"];
 
            //处理歌曲下载页面的URL
            NSArray * myURLTmpArr = [mySubArr objectAtIndex:0] componentsSeparatedByString:@"\" title=\"请点击左键!来源网址: "];
            myURLTmpArr = [mySubArr objectAtIndex:0] componentsSeparatedByString:@"\""];
 
            NSMutableString * SongsURL = [myURLTmpArr objectAtIndex:1];
            //[SongsURL stringByAddingPercentEscapesUsingEncoding:enc];
 
            //NSLog(@"url= %@",SongsURL);
 
            for (int j=0; j<[mySubArr count]; j++) {
                NSLog(@"%d= %@",j,[mySubArr objectAtIndex:j]);
            }
 
 
            //如果只有一段,表示 无 歌手名 和 专辑名
            //if ([mySubArr count]<=1) {
 
 
            //NSLog()
            //常量定义 段的意义
            const int Const_Songs = 0;
            const int Const_Singer = 1;
            const int Const_Album = 4;
            //变量定义
            NSMutableString * SongsName = (NSMutableString*)@"";
            NSString * SongsSinger = @"";
            NSString * SongsAlbum = @"";
            NSString * SongsSpeed = @"";
            NSString * SongsSize = @"";
 
            //处理 歌曲大小
            NSMutableArray * mySizeArr = (NSMutableArray*)[mySubArr objectAtIndex:([mySubArr count]-1)] componentsSeparatedByString:@"<td>"];
            if ([mySizeArr count]>=2) {
                SongsSize = [mySizeArr objectAtIndex:([mySizeArr count]-2)];
                NSLog(@"size = %@",SongsSize);
            };
 
            //处理 歌曲链接速度图片
            @try {
 
                if ([mySubArr count]>=3) {
                    if ([mySubArr objectAtIndex:([mySubArr count]-1)]!=nil) {
 
                        NSMutableArray * mySpeedArr = (NSMutableArray*)[mySubArr objectAtIndex:([mySubArr count]-1)] componentsSeparatedByString:@"<td class=spd><img src=\"http://img.baidu.com/img/mp3/"];
 
                        if ([mySpeedArr count]>0)
                            if ([mySpeedArr objectAtIndex:1]!=nil)
                                mySpeedArr = (NSMutableArray*)[mySpeedArr objectAtIndex:1] componentsSeparatedByString:@"\"></td>"];
 
                        if ([mySpeedArr objectAtIndex:0]!=nil)
                            SongsSpeed = [mySpeedArr objectAtIndex:0];
 
                        NSLog(@"test speed = %@",SongsSpeed);
                    }
                };
 
            }
            @catch (NSException * e) {
                //none
            }
            @finally {
                //none
            }
 
            //处理 歌曲名
            NSMutableArray * myTmpArr = (NSMutableArray *)[mySubArr objectAtIndex:Const_Songs] componentsSeparatedByString:@"\"return ow(event,this)\" target=\"_blank\">"];
            myTmpArr = (NSMutableArray *)[myTmpArr objectAtIndex:1] componentsSeparatedByString:@"</a></td>"];
            SongsName = [myTmpArr objectAtIndex:0];
            NSString * mySubStr;
 
            //处理 歌手名
            if ([mySubArr count]>1) {
                mySubStr = [mySubArr objectAtIndex:Const_Singer];
                SongsSinger = mySubStr;
            };
 
            //处理 专辑名
            if ([mySubArr count]>=5) {
                mySubStr = [mySubArr objectAtIndex:Const_Album];
                NSMutableArray * mySubSubArr = (NSMutableArray *)[mySubStr componentsSeparatedByString:@"</a>"];
                mySubStr = [mySubSubArr objectAtIndex:0];
                SongsAlbum = mySubStr;
 
            } else {
                SongsAlbum = @"";
            };
 
            //处理: 歌曲名中如果包含歌词
            NSMutableString *tmp = [NSMutableString stringWithString:SongsName];
            NSRange range = [tmp rangeOfString:@"<br><font color=\"#999999\" class=f10>"];
            if (range.location != NSNotFound) {
                range.length = SongsName.length - range.location;
                //NSLog(@"%d !",range.length);
                [tmp deleteCharactersInRange:range];
                //NSLog(@"test =%@",tmp);
                SongsName = tmp;
            }
            //[tmp release];
 
            //NSLog(@"t= %@, %@ , %@",SongsName,SongsSinger,SongsAlbum);
 
            
            NSString * FinalStr = [[NSString alloc] initWithFormat:@"<头>%@<分割>%@<分割>%@<分割>%@<分割>%@<分割>%@",
                                    SongsName,SongsSinger,SongsAlbum,SongsURL,SongsSpeed,SongsSize] autorelease];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"<font color=\"#c60a00\">" withString:@""];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"</font>" withString:@""];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"</a>" withString:@""];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"<a href=\"http://mp3.baidu.com/singerlist/" withString:@""];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@" " withString:@""];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"'" withString:@"'"];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"<头> " withString:@"<头>"];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"<头>" withString:@""];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"&" withString:@"&"];
            FinalStr = [FinalStr stringByReplacingOccurrencesOfString:@"</td>" withString:@""];
            FinalStr = [FinalStr stringByReplacingPercentEscapesUsingEncoding:enc];
 
            //if ([SongsURL hasSuffix:@"3"]) {
            [mySongs addObject:FinalStr];
            //};
            //]
        }
        @catch (NSException * e) {
            //
        }
        @finally {
            // none
        }
 
    };
 
    [myResponseStr release];
 
    return (NSArray *)mySongs;
 
}
 
 
+(NSString*)decodeBaiduURL:(NSString*)myEncodeURL{
    //
 
    NSString * returnURL = [[NSString alloc] initWithFormat:@""] autorelease];
    //char *myCEncodeURL = [myEncodeURL cStringcStringWithEncoding:NSASCIIStringEncoding];
    NSLog(@"input %@",myEncodeURL);
    //字串
    static NSString * myConst = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    int pyl ; // 偏移量
    //NSRange myRange = [myEncodeURL rangeOfString:@":"]; //定位 协议标识符
    UniChar myUniChr = [myEncodeURL characterAtIndex:0]; //取出第一字符
    //转换类型
    NSString * myChrAsStr = [[NSString alloc] initWithFormat:@"%C",myUniChr] autorelease];
    //确定第一字符在字串中的位置
    NSRange myRange2 = [myConst rangeOfString:myChrAsStr];
    int myFirstChrLocation = myRange2.location;
 
    //计算偏移量
    pyl = myFirstChrLocation - 33 ;
    // 33 means "h" 's location .
 
    NSLog(@"len = %d",myEncodeURL.length);
    //还原字串
    //NSLog(@"pyl = %d",pyl);
    for (int i=0; i<[myEncodeURL length]; i++) {
        UniChar myTmpChr= [myEncodeURL characterAtIndex:i];
        NSString * myTmpChrAsStr = [[NSString alloc] initWithFormat:@"%C",myTmpChr] autorelease];
        NSRange myTmpRange = [myConst rangeOfString: myTmpChrAsStr];
        if (myTmpRange.location != NSNotFound) {
            int newChrAsInt = myTmpRange.location - pyl;
            //NSLog(@"pyl = %d , oldchr = %C , oldcount = %d, newcount = %d",pyl,myTmpChr,
            //hai myTmpRange.location,newChrAsInt);
            if (newChrAsInt<0) {
                newChrAsInt = newChrAsInt + 62;
                //NSLog(@"%d",newChrAsInt);
            } else {
                if (newChrAsInt>62) {
                    newChrAsInt = newChrAsInt % 62;
                };
            }
            /// NSLog(@"! pyl = %d , oldchr = %C , oldcount = %d, newcount = %d",pyl,myTmpChr,
            // myTmpRange.location,newChrAsInt);
            myTmpChr = [myConst characterAtIndex:newChrAsInt];
        };
        //NSLog(@"%C",myTmpChr);
        returnURL= [returnURL stringByAppendingFormat:@"%C",myTmpChr];
    }
 
    returnURL= [returnURL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
    NSLog(@"output %@",returnURL);
    return returnURL;
 
}
 
+(NSString*)DownPageURLToMusicFileURL:(NSString*)myDownpage{
    NSURL * myURL = [NSURL URLWithString:myDownpage];
 
    ASIHTTPRequest * myRequest = [[ASIHTTPRequest alloc] initWithURL:myURL] autorelease];
    [myRequest startSynchronous];
 
 
    NSData * myResponseData = [myRequest responseData];
    NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding (kCFStringEncodingGB_18030_2000);
    NSString * myResponseStr = [NSString alloc] initWithData:myResponseData encoding:enc];
 
    //NSLog(@"resstr= %@", myResponseStr);
 
    NSArray *myArr = [myResponseStr componentsSeparatedByString:@"var encurl = \""];
 
    myArr = [myArr objectAtIndex:1] componentsSeparatedByString:@"\", newurl = \"\";"];
 
    [myResponseStr release];
 
    return [self decodeBaiduURL:[myArr objectAtIndex:0];

//

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值