Monthly Archives: July 2014

HTML5演示Demo

Just clone some html5 js code from lightapp & make a demo. It’s used to build simple app for book, manual and posters. It supports audio, video & baidu map, etc.
刚刚从lightapp上克隆了一些javascript代码,用于手机端展示html5动态页面的,可以非常方便的制作一些简单的宣传类应用,它支持声音,视频,百度地图展示等功能。

It’s here. 猛击这里展示。 直接输入:http://airflypan.com/ttpogx/ 也行。

iOS日期处理

Dates

        NSDate类提供了创建date,比较date以及计算两个date之间间隔的功能。Date对象是不可改变的。

        如果你要创建date对象并表示当前日期,你可以alloc一个NSDate对象并调用init初始化:

  1. NSDate *now = [[NSDate alloc] init];  

        或者使用NSDate的date类方法来创建一个日期对象。如果你需要与当前日期不同的日期,你可以使用NSDate的initWithTimeInterval…或dateWithTimeInterval…方法,你也可以使用更复杂的calendar或date components对象。

        创建一定时间间隔的NSDate对象:

  1. NSTimeInterval secondsPerDay = 24 * 60 * 60;  
  2.   
  3. NSDate *tomorrow = [[NSDate alloc] initWithTimeIntervalSinceNow:secondsPerDay];  
  4.   
  5. NSDate *yesterday = [[NSDate alloc] initWithTimeIntervalSinceNow:-secondsPerDay];  
  6.   
  7. [tomorrow release];  
  8. [yesterday release];  


        使用增加时间间隔的方式来生成NSDate对象:

  1. NSTimeInterval secondsPerDay = 24 * 60 * 60;  
  2.   
  3. NSDate *today = [[NSDate alloc] init];  
  4. NSDate *tomorrow, *yesterday;  
  5.   
  6. tomorrow = [today dateByAddingTimeInterval: secondsPerDay];  
  7. yesterday = [today dateByAddingTimeInterval: -secondsPerDay];  
  8.   
  9. [today release];  


        如果要对NSDate对象进行比较,可以使用isEqualToDate:, compare:, laterDate:和 earlierDate:方法。这些方法都进行精确比较,也就是说这些方法会一直精确比较到NSDate对象中秒一级。例如,你可能比较两个日期,如果他们之间的间隔在一分钟之内则认为这两个日期是相等的。在这种情况下使用,timeIntervalSinceDate:方法来对两个日期进行比较。下面的代码进行了示例:

  1. if (fabs([date2 timeIntervalSinceDate:date1]) < 60) …  

 

NSCalendar & NSDateComponents

        日历对象封装了对系统日期的计算,包括这一年开始,总天数以及划分。你将使用日历对象对绝对日期与date components(包括年,月,日,时,分,秒)进行转换。

        NSCalendar定义了不同的日历,包括佛教历,格里高利历等(这些都与系统提供的本地化设置相关)。NSCalendar与NSDateComponents对象紧密相关。

        你可以通过NSCalendar对象的currentCalendar方法来获得当前系统用户设置的日历。

  1. NSCalendar *currentCalendar = [NSCalendar currentCalendar];  
  2.   
  3. NSCalendar *japaneseCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSJapaneseCalendar];  
  4.   
  5. NSCalendar *usersCalendar = [[NSLocale currentLocale] objectForKey:NSLocaleCalendar];  

        usersCalendar和currentCalendar对象是相等的,尽管他们是不同的对象。

        你可以使用NSDateComponents对象来表示一个日期对象的组件——例如年,月,日和小时。如果要使一个NSDateComponents对象有意义,你必须将其与一个日历对象相关联。下面的代码示例了如何创建一个NSDateComponents对象:

  1. NSDateComponents *components = [[NSDateComponents alloc] init];  
  2.   
  3. [components setDay:6];  
  4. [components setMonth:5];  
  5. [components setYear:2004];  
  6.   
  7. NSInteger weekday = [components weekday]; // Undefined (== NSUndefinedDateComponent)  


        要将一个日期对象解析到相应的date components,你可以使用NSCalendar的components:fromDate:方法。此外日期本身,你需要指定NSDateComponents对象返回组件。

  1. NSDate *today = [NSDate date];  
  2.   
  3. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  4.   
  5. NSDateComponents *weekdayComponents = [gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];  
  6.   
  7. NSInteger day = [weekdayComponents day];  
  8. NSInteger weekday = [weekdayComponents weekday];  
  9.   
  10. 同样你也可以从NSDateComponents对象来创建NSDate对象:  
  11. NSDateComponents *components = [[NSDateComponents alloc] init];  
  12.   
  13. [components setWeekday:2]; // Monday  
  14. [components setWeekdayOrdinal:1]; // The first Monday in the month  
  15. [components setMonth:5]; // May  
  16. [components setYear:2008];  
  17.   
  18. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  19.   
  20. NSDate *date = [gregorian dateFromComponents:components];  


        为了保证正确的行为,您必须确保使用的组件在日历上是有意义的。指定“出界”日历组件,如一个-6或2月30日在公历中的日期值产生未定义的行为。

        你也可以创建一个不带年份的NSDate对象,这样的操作系统会自动生成一个年份,但在后面的代码中不会使用其自动生成的年份。

  1. NSDateComponents *components = [[NSDateComponents alloc] init];  
  2.   
  3. [components setMonth:11];  
  4. [components setDay:7];  
  5.   
  6. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  7.   
  8. NSDate *birthday = [gregorian dateFromComponents:components];  


        下面的示例显示了如何从一个日历置换到另一个日历:

  1. NSDateComponents *comps = [[NSDateComponents alloc] init];  
  2.   
  3. [comps setDay:6];  
  4. [comps setMonth:5];  
  5. [comps setYear:2004];  
  6.   
  7. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  8.   
  9. NSDate *date = [gregorian dateFromComponents:comps];  
  10.   
  11. [comps release];  
  12. [gregorian release];  
  13.   
  14. NSCalendar *hebrew = [[NSCalendar alloc] initWithCalendarIdentifier:NSHebrewCalendar];  
  15.   
  16. NSUInteger unitFlags = NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit;  
  17.   
  18. NSDateComponents *components = [hebrew components:unitFlags fromDate:date];  
  19.   
  20. NSInteger day = [components day]; // 15  
  21. NSInteger month = [components month]; // 9  
  22. NSInteger year = [components year]; // 5764  

 

历法计算

        在当前时间加上一个半小时:

  1. NSDate *today = [[NSDate alloc] init];  
  2.   
  3. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  4.   
  5. NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];  
  6.   
  7. [offsetComponents setHour:1];  
  8. [offsetComponents setMinute:30];  
  9.   
  10. // Calculate when, according to Tom Lehrer, World War III will end  
  11. NSDate *endOfWorldWar3 = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];  


        获得当前星期中的星期天(使用格里高利历):

  1. NSDate *today = [[NSDate alloc] init];  
  2.   
  3. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  4.   
  5. // Get the weekday component of the current date  
  6. NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:today];  
  7.   
  8. /*  
  9. Create a date components to represent the number of days to subtract from the current date.  
  10.   
  11. The weekday value for Sunday in the Gregorian calendar is 1, so subtract 1 from the number of days to subtract from the date in question.  (If today is Sunday, subtract 0 days.)  
  12. */  
  13.   
  14. NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];  
  15.   
  16. [componentsToSubtract setDay: 0 – ([weekdayComponents weekday] – 1)];  
  17.   
  18. NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0];  
  19.   
  20. /*  
  21. Optional step:  
  22. beginningOfWeek now has the same hour, minute, and second as the original date (today).  
  23.   
  24. To normalize to midnight, extract the year, month, and day components and create a new date from those components.  
  25. */  
  26.   
  27. NSDateComponents *components = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate: beginningOfWeek];  
  28.   
  29. beginningOfWeek = [gregorian dateFromComponents:components];  

        如何可以计算出一周的第一天(根据系统的日历设置):

  1. NSDate *today = [[NSDate alloc] init];  
  2.   
  3. NSDate *beginningOfWeek = nil;  
  4.   
  5. BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek interval:NULL forDate: today];  


        获得两个日期之间的间隔:

  1. NSDate *startDate = …;  
  2. NSDate *endDate = …;  
  3.   
  4. NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  5.   
  6. NSUInteger unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;  
  7.   
  8. NSDateComponents *components = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0];  
  9.   
  10. NSInteger months = [components month];  
  11. NSInteger days = [components day];  

        使用Category来计算同一时代(AD|BC)两个日期午夜之间的天数:

  1. @implementation NSCalendar (MySpecialCalculations)  
  2.   
  3. -(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate {  
  4.      NSInteger startDay=[self ordinalityOfUnit:NSDayCalendarUnit inUnit: NSEraCalendarUnit forDate:startDate];  
  5.   
  6.      NSInteger endDay=[self ordinalityOfUnit:NSDayCalendarUnit inUnit: NSEraCalendarUnit forDate:endDate];  
  7.   
  8.      return endDay-startDay;  
  9. }  
  10.   
  11. @end  


        使用Category来计算不同时代(AD|BC)两个日期的天数:

  1. @implementation NSCalendar (MyOtherMethod)  
  2.   
  3. -(NSInteger) daysFromDate:(NSDate *) startDate toDate:(NSDate *) endDate {  
  4.   
  5.      NSCalendarUnit units=NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;  
  6.   
  7.      NSDateComponents *comp1=[self components:units fromDate:startDate];  
  8.      NSDateComponents *comp2=[self components:units fromDate endDate];  
  9.   
  10.      [comp1 setHour:12];  
  11.      [comp2 setHour:12];  
  12.   
  13.      NSDate *date1=[self dateFromComponents: comp1];  
  14.      NSDate *date2=[self dateFromComponents: comp2];  
  15.   
  16.      return [[self components:NSDayCalendarUnit fromDate:date1 toDate:date2 options:0] day];  
  17. }  
  18.   
  19. @end  


        判断一个日期是否在当前一周内(使用格里高利历):

  1. -(BOOL)isDateThisWeek:(NSDate *)date {  
  2.   
  3.      NSDate *start;  
  4.      NSTimeInterval extends;  
  5.   
  6.      NSCalendar *cal=[NSCalendar autoupdatingCurrentCalendar];  
  7.      NSDate *today=[NSDate date];  
  8.   
  9.      BOOL success= [cal rangeOfUnit:NSWeekCalendarUnit startDate:&start interval: &extends forDate:today];  
  10.   
  11.      if(!success)  
  12.         return NO;  
  13.   
  14.      NSTimeInterval dateInSecs = [date timeIntervalSinceReferenceDate];  
  15.      NSTimeInterval dayStartInSecs= [start timeIntervalSinceReferenceDate];  
  16.   
  17.      if(dateInSecs > dayStartInSecs && dateInSecs < (dayStartInSecs+extends)){  
  18.           return YES;  
  19.      }  
  20.      else {  
  21.           return NO;  
  22.      }  
  23. }  

iOS将字符串转换为日期时间格式

1、如何如何将一个字符串如“ 20110826134106”装化为任意的日期时间格式,下面列举两种类型:
   NSString* string = @”20110826134106″;
    NSDateFormatter *inputFormatter = [[[NSDateFormatter alloc] init] autorelease];
    [inputFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@”en_US”] autorelease]];
    [inputFormatter setDateFormat:@”yyyyMMddHHmmss”];
    NSDate* inputDate = [inputFormatter dateFromString:string];
    NSLog(@”date = %@”, inputDate);
    
    NSDateFormatter *outputFormatter = [[[NSDateFormatter alloc] init] autorelease]; 
    [outputFormatter setLocale:[NSLocale currentLocale]];
    [outputFormatter setDateFormat:@”yyyy年MM月dd日 HH时mm分ss秒”];
    NSString *str = [outputFormatter stringFromDate:inputDate];
    NSLog(@”testDate:%@”, str);
两次打印的结果为:
    date = 2011-08-26 05:41:06 +0000
    testDate:2011年08月26日 13时41分06秒

说明:上面的时间是美国时间,下面的没有设置

   NSString* string = @”Wed, 05 May 2011 10:50:00 +0800″;
    NSDateFormatter *inputFormatter = [[[NSDateFormatter alloc] init] autorelease];
    [inputFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@”en_US”] autorelease]];
    [inputFormatter setDateFormat:@”EEE, d MMM yyyy HH:mm:ss Z”];
    NSDate* inputDate = [inputFormatter dateFromString:string];
    NSLog(@”date = %@”, inputDate);

2、以前一直为这个事情纠结,无奈只能拼接字符串:

NSString *str=@”20120403000000″;

NSString *dateStr=[NSString stringWithFormat:@”有效期至:%@年%@月%@日”,
                           [str substringWithRange:NSMakeRange(0, 4)],
                           [str substringWithRange:NSMakeRange(4, 2)],
                           [str substringWithRange:NSMakeRange(6, 2)]];
这个方法笨,可是没办法,查了好多资料,都没明白,今天突然明白了,呵呵,只要把那个[inputFormatter setDateFormat:@”EEE, d MMM yyyy HH:mm:ss Z”];@“”里面的格式转化为你字符串的格式一切就OK了,不知道我说明白了吗?


3、iOS-NSDateFormatter 格式说明:

G: 公元时代,例如AD公元
    yy: 年的后2位
    yyyy: 完整年
    MM: 月,显示为1-12
    MMM: 月,显示为英文月份简写,如 Jan
    MMMM: 月,显示为英文月份全称,如 Janualy
    dd: 日,2位数表示,如02
    d: 日,1-2位显示,如 2
    EEE: 简写星期几,如Sun
    EEEE: 全写星期几,如Sunday
    aa: 上下午,AM/PM
    H: 时,24小时制,0-23
    K:时,12小时制,0-11
    m: 分,1-2位
    mm: 分,2位
    s: 秒,1-2位
    ss: 秒,2位
    S: 毫秒

常用日期结构:
yyyy-MM-dd HH:mm:ss.SSS
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd
MM dd yyyy

iOS开发UITableView中行的操作

文章写得很好,转载自:http://my.oschina.net/plumsoft/blog/53271

这篇文章主要讲的表格的操作包括:标记行、移动行、删除行、插入行。

这次就不从头建立工程了,在http://www.oschina.net/code/snippet_164134_9876下载工程。这个工程就是最简单的产生一个表格并向其中写入数据。用Xcode 4.2打开它,在这个工程基础上实现以上操作。

1、标记行

这里讲的标记行指的是单击此行,可以实现在此行右边出现一个勾,如下图所示:

为了实现标记功能,在ViewController.m中@end之前添加代码:

#pragma mark -
#pragma mark Table Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *oneCell = [tableView cellForRowAtIndexPath: indexPath];
    if (oneCell.accessoryType == UITableViewCellAccessoryNone) {
        oneCell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else 
        oneCell.accessoryType = UITableViewCellAccessoryNone;
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
}

该代码实现:单击某行时,若此行未被标记,则标记此行;若此行已经被标记,则取消标记。

运行效果如上图。

上面的代码实际上就是修改某行的accessoryType属性,这个属性可以设为四个常量:

UITableViewCellAccessoryCheckmark
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryNone

效果依次如下图所示:

            

   UITableViewCellAccessoryCheckmark            UITableViewCellAccessoryDetailDisclosureButton

                 

UITableViewCellAccessoryDisclosureIndicator                   UITableViewCellAccessoryNone

注意,上面第二张图片中的蓝色圆圈不仅仅是一个图标,还是一个控件,点击它可以触发事件,在上一篇博客《iOS开发16:使用Navigation Controller切换视图》使用过。

2、移动行

想要实现移动或者删除行这样的操作,需要启动表格的编辑模式。使用的是setEditing:animated:方法。

2.1 打开ViewController.xib,将其中的表格控件映射成Outlet到ViewController.h,名称为myTableView。

2.2 打开ViewController.m,在viewDidLoad方法最后添加代码:

//启动表格的编辑模式
[self.myTableView setEditing:YES animated:YES];

2.3 在@end之前添加代码:

//打开编辑模式后,默认情况下每行左边会出现红的删除按钮,这个方法就是关闭这些按钮的
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
           editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return UITableViewCellEditingStyleNone; 
} 

//这个方法用来告诉表格 这一行是否可以移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 
    return YES; 
}

//这个方法就是执行移动操作的
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)
        sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    NSUInteger fromRow = [sourceIndexPath row]; 
    NSUInteger toRow = [destinationIndexPath row]; 
    
    id object = [list objectAtIndex:fromRow]; 
    [list removeObjectAtIndex:fromRow]; 
    [list insertObject:object atIndex:toRow]; 
}

editingStyleForRowAtIndexPath这个方法中用到了常量UITableViewCellEditingStyleNone,它表示不可编辑,这里的编辑指的是删除和插入。表示表格行的编辑模式的常量有:

UITableViewCellEditingStyleDelete
UITableViewCellEditingStyleInsert
UITableViewCellEditingStyleNone

顾名思义,第一个表示删除,第二个表示插入,第三个表示不可编辑。

若将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleNone依次换成上面三个值,则它们运行的效果依次如下图所示:

      

2.4 运行,从下图可以看到实现了行的移动:

但是也会发现,现在无法对每行进行标记了。这说明,在编辑模式下,无法选择行,从而didSelectRowAtIndexPath这个方法不会执行。

3、删除行

从第2步过来,实现删除某行,其实比较简单了。

3.1将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleNone修改成UITableViewCellEditingStyleDelete。

3.2 在@end之前添加代码:

//这个方法根据参数editingStyle是UITableViewCellEditingStyleDelete
//还是UITableViewCellEditingStyleDelete执行删除或者插入
- (void)tableView:(UITableView *)tableView commitEditingStyle:
    (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger row = [indexPath row];
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [self.list removeObjectAtIndex:row]; 
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationAutomatic]; 
    }
}

在这个方法中又出现了一个常量:UITableViewRowAnimationAutomatic,它表示删除时的效果,类似的常量还有:

UITableViewRowAnimationAutomatic
UITableViewRowAnimationTop
UITableViewRowAnimationBottom
UITableViewRowAnimationLeft
UITableViewRowAnimationRight
UITableViewRowAnimationMiddle
UITableViewRowAnimationFade
UITableViewRowAnimationNone

它们的效果就不一一介绍了,可以在实际使用时试试。

3.3 运行,看看效果:

      

刚运行时显示如左边的图片,点击某一行左边的圆圈图标,会显示如中间图片所示。然后点击Delegate按钮,那一行就会被删除掉,如右边的那张图片所示,它显示的是删除时的效果。

4、插入行

这个与删除行类似。

4.1 首先将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleDelete修改成UITableViewCellEditingStyleInsert。

4.2在3.2添加的方法中添加代码:

else {
    //我们实现的是在所选行的位置插入一行,因此直接使用了参数indexPath
    NSArray *insertIndexPaths = [NSArray arrayWithObjects:indexPath,nil];
    //同样,将数据加到list中,用的row
    [self.list insertObject:@"新添加的行" atIndex:row];
    [tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
}

上面的代码中也可以不用insertRowsAtIndexPaths方法,而直接使用[tableView reloadData];语句,但是这样就没有添加的效果了。

4.3 好了,运行一下:

      

刚运行时如上面左图所示,单击了某个加号后,新的一行就从右边飞进来了,因为在insertRowsAtIndexPaths中用了参数UITableViewRowAnimationRight。

Objective-C中的Class(类类型),Selector(选择器SEL),函数指针(IMP)

看到了一篇牛文“Objective-C 2.0 with Cocoa Foundation— 5,Class类型,选择器Selector以及函数指针”,讲得十分精彩,忍不住把它的代码加上注释整理于此,以便日后查看。
个人体会:obj-C中的“Class类型变量”比c#中的Object基类还要灵活,可以用它生成任何类型的实例(但是它又不是NSObject)。而选择器SEL与函数指针IMP,如果非要跟c#扯上关系的话,这二个结合起来,就点类似c#中的反射+委托,可以根据一个方法名称字符串,直接调用方法。
“牛”的基类 Cattle.h
1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
@interface Cattle : NSObject {
    int legsCount;
}
- (void)saySomething;
- (void)setLegsCount:(int) count;
@end
 Cattle.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "Cattle.h"
@implementation Cattle
-(void) saySomething
{
    NSLog(@"Hello, I am a cattle, I have %d legs.", legsCount);
}
-(void) setLegsCount:(int) count
{
    legsCount = count;
}
@end
子类“公牛” Bull.h
1
2
3
4
5
6
7
8
9
10
#import <Foundation/Foundation.h>
#import "Cattle.h"
@interface Bull : Cattle {
    NSString *skinColor;
}
- (void)saySomething;
- (NSString*) getSkinColor;
- (void) setSkinColor:(NSString *) color;
@end
Bull.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import "Bull.h"
@implementation Bull
-(void) saySomething
{
    NSLog(@"Hello, I am a %@ bull, I have %d legs.", [self getSkinColor],legsCount);
}
-(NSString*) getSkinColor
{
    return skinColor;
}
- (void) setSkinColor:(NSString *) color
{
    skinColor = color;
}
@end
代理类DoProxy.h (关键的代码都在这里)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import <Foundation/Foundation.h>
//定义几个字符串常量
#define SET_SKIN_COLOR @"setSkinColor:"
#define BULL_CLASS @"Bull"
#define CATTLE_CLASS @"Cattle"
@interface DoProxy : NSObject {
    BOOL notFirstRun;
    
    id cattle[3];
    //定义二个选择器
    SEL say;
    SEL skin;
    
    //定义一个函数指针(传统C语言的处理方式)
    void(*setSkinColor_Func)(id,SEL,NSString*);
    
    //定义一个IMP方式的函数指针(obj-C中推荐的方式)
    IMP say_Func;
    
    //定义一个类
    Class bullClass;
}
-(void) doWithCattleId:(id) aCattle colorParam:(NSString*) color;
-(void) setAllIVars;
-(void) SELFuncs;
-(void) functionPointers;
@end
DoProxy.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#import "DoProxy.h"
#import "Cattle.h"
#import "Bull.h"
@implementation DoProxy
//初始化所有变量
- (void) setAllIVars
{  
    cattle[0] = [Cattle new];
    
    bullClass = NSClassFromString(BULL_CLASS);
    //即cattle[1],cattle[2]都是Bull类的实例
    cattle[1] = [bullClass new];
    cattle[2] = [bullClass new];
    
    say = @selector(saySomething);
    skin = NSSelectorFromString(SET_SKIN_COLOR);
}
//初始化id
- (void) doWithCattleId:(id) aCattle colorParam:(NSString*) color
{
    //第一次运行的时候
    if(notFirstRun == NO)
    {
        NSString *myName = NSStringFromSelector(_cmd);//取得当前正在执行的方法的名字
        NSLog(@"Running in the method of %@", myName);
        notFirstRun = YES;//修改初次运行标志位
    }
    
    NSString *cattleParamClassName = [aCattle className];//取得aCattle的"类名称"
    
    //如果aCattle是Bull或Cattle类的实例
    if([cattleParamClassName isEqualToString:BULL_CLASS] || [cattleParamClassName isEqualToString:CATTLE_CLASS])
    {
        [aCattle setLegsCount:4];//设置牛的4条腿
        if([aCattle respondsToSelector:skin])//如果aCattle对应的是类中,有定义方法"setSkinColor"
        {
            [aCattle performSelector:skin withObject:color];//则调用setSkinColor方法
        }
        else
        {
            NSLog(@"Hi, I am a %@, have not setSkinColor!", cattleParamClassName);//否则输出相应的提示信息
        }
        [aCattle performSelector:say];//最后执行saySomething方法(这二个方法在Bull与Cattle类中都有,所以肯定能运行)
    }
    else //如果aCattle即不是Bull类也不是Cattle类的实例
    {
        NSString *yourClassName = [aCattle className];
        NSLog(@"Hi, you are a %@, but I like cattle or bull!", yourClassName);//显示这个"异类"的相关信息
    }
}
//初始化选择器以及相应函数
- (void) SELFuncs
{
    [self doWithCattleId:cattle[0] colorParam:@"brown"];
    [self doWithCattleId:cattle[1] colorParam:@"red"];
    [self doWithCattleId:cattle[2] colorParam:@"black"];
    [self doWithCattleId:self colorParam:@"haha"];//这里故意传入一个异类self(即DoProxy本身),DoProxy当然不是Bull或Cattle
}
//函数指针测试
- (void) functionPointers
{
    //取得函数指针的第一种方式
    setSkinColor_Func=(void (*)(id, SEL, NSString*)) [cattle[1] methodForSelector:skin];
    //上面的语句其实等效于下面这种方法
    //IMP setSkinColor_Func = [cattle[1] methodForSelector:skin];
    
    //用第二种方法取得saySomething的函数指针
    say_Func = [cattle[1] methodForSelector:say];
    
    //用函数指针的形式调用setSkinColor
    setSkinColor_Func(cattle[1],skin,@"verbose");
    
    NSLog(@"Running as a function pointer will be more efficiency!");
    
    //调用saySomething方法
    say_Func(cattle[1],say);
}
@end
测试主函数main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <Foundation/Foundation.h>
#import "DoProxy.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    DoProxy *doProxy = [DoProxy new];
    
    [doProxy setAllIVars];
    [doProxy SELFuncs];
    [doProxy functionPointers];
    
    [doProxy release];
    [pool drain];
    return 0;
}

运行结果:

2011-02-28 21:40:33.240 HelloSelector[630:a0f] Running in the method of doWithCattleId:colorParam:
2011-02-28 21:40:33.245 HelloSelector[630:a0f] Hi, I am a Cattle, have not setSkinColor!
2011-02-28 21:40:33.247 HelloSelector[630:a0f] Hello, I am a cattle, I have 4 legs.
2011-02-28 21:40:33.248 HelloSelector[630:a0f] Hello, I am a red bull, I have 4 legs.
2011-02-28 21:40:33.250 HelloSelector[630:a0f] Hello, I am a black bull, I have 4 legs.
2011-02-28 21:40:33.251 HelloSelector[630:a0f] Hi, you are a DoProxy, but I like cattle or bull!
2011-02-28 21:40:33.252 HelloSelector[630:a0f] Running as a function pointer will be more efficiency!
2011-02-28 21:40:33.254 HelloSelector[630:a0f] Hello, I am a verbose bull, I have 4 legs.

作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

Objective-c的动态调用函数的方法

最近在看关于selector的资料,感觉很好玩。

首先我能理解什么叫selector已经不容易了,查阅了很多资料。
其次是要动态调用,首先网上找到的方法是,这样的用法:

-(void)traceThem:(int)a traceThem2:(int)b{

NSLog(@”hello:%d 你好%d”,a,b);

}

[self performSelector:@selector(traceThem:traceThem2:) withObject:(id)1 withObject:(id)2];

上面代码的意思要调用函数名为traceThem:traceThem2:的函数,参数分别是1,2

(OC就叫发消息,它的函数说法是有一条traceThem:traceThem2:的消息,reciver是self,其实编译的时候还不是自己改成调用函数的概念。);

performSelector这样的调用函数方法,最多只能支持2个参数,你可以把参数放到NSDictionary传递。

搞到百度到的一大堆blog文都是自己写了一大段代码来支持performSelector多个参数的调用。。。

其实还有个好方法objc_msgSend:

objc_msgSend(self,@selector(traceThem:traceThem2:traceThme3:),参数1,参数2,参数3);

但是动态调用,就是要求@selector()的参数能动态输入,例如是配置到一个配置表中的字符串(NSString),方法如下:

SEL function = NSSelectorFromString(@”traceThem:traceThem2:traceThem3:”);

objc_msgSend(self,function,1,2,3);

BTW:

由于objc_msgSend是运行时的方法,所以要加入头文件,用open quickly可帮到大忙,如下:

,即需要的头文件:#import <objc/message.h>

 

objective-c的动态调用函数的方法 - Sylar_Lin - 低调做人高调做事