如何在objective c 绝对值-c 传递通过 UIColorFromRGB 的值

Objective-C的消息传递机制 - pengyingh - 博客园
各种语言都有些传递函数的方法:C语言中可以使用函数指针,C++中有函数引用、仿函数和lambda,Objective-C里也有选择器(selector)和block。不过由于iOS SDK中的大部分API都是selector的方式,所以本文就重点讲述selector了。Objective-C和我接触过的其他面向对象的语言不同,它强调消息传递,而非方法调用。因此你可以对一个对象传递任何消息,而不需要在编译期声名这些消息的处理方法。很显然,既然编译期并不能确定方法的地址,那么运行期就需要自行定位了。而Objective-C runtime就是通过&id objc_msgSend(id theReceiver, SEL theSelector, ...)&这个函数来调用方法的。其中theReceiver是调用对象,theSelector则是消息名,省略号就是C语言的不定参数了。这里的消息名是SEL类型,它被定义为struct objc_selector *。不过文档中并没有透露objc_selector是什么东西,但提供了@selector指令来生成:
SEL selector = @selector(message);
@selector是在编译期计算的,所以并不是函数调用。更进一步的测试表明,它在Mac OS X 10.6和iOS下都是一个C风格的字符串(char*):
NSLog (@"%s", (char *)selector);
你会发现结果是&message&这个消息名。下面就写个测试类:
@interface Test : NSObject@end@implementation Test- (NSString *)intToString:(NSInteger)number {
return [NSString stringWithFormat:@"%d", number];}- (NSString *)doubleToString:(double *)number {
return [NSString stringWithFormat:@"%f", *number];}- (NSString *)pointToString:(CGPoint)point {
return [NSString stringWithFormat:@"{%f, %f}", point.x, point.y];}- (NSString *)intsToString:(NSInteger)number1 second:(NSInteger)number2 third:(NSInteger)number3 {
return [NSString stringWithFormat:@"%d, %d, %d", number1, number2, number3];}- (NSString *)doublesToString:(double)number1 second:(double)number2 third:(double)number3 {
return [NSString stringWithFormat:@"%f, %f, %f", number1, number2, number3];}- (NSString *)combineString:(NSString *)string1 withSecond:string2 withThird:string3 {
return [NSString stringWithFormat:@"%@, %@, %@", string1, string2, string3];}@end
再来测试下objc_msgSend:
#import &objc/message.h&//要使用objc_msgSend的话,就要引入这个头文件Test *test = [[Test alloc] init];CGPoint point = {123, 456};NSLog(@"%@", objc_msgSend(test, @selector(pointToString:), point));[test release];
结果是&{123.6.000000}&。而且与之前猜想的一样,下面这样调用也是可以的:
NSLog(@"%@", objc_msgSend(test, (SEL)"pointToString:", point));
看到这里你应该发现了,这种实现方式只能确定消息名和参数数目,而参数类型和返回类型就给抹杀了。所以编译器只能在编译期警告你参数类型不对,而无法阻止你传递类型错误的参数。接下来再看看NSObject协议提供的一些传递消息的方法:
- (id)performSelector:(SEL)aSelector
- (id)performSelector:(SEL)aSelector withObject:(id)anObject
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
也没有觉得很无语?为什么参数必须是对象?为什么最多只支持2个参数?好在selector本身也不在乎参数类型,所以传个不是对象的玩意也行:
NSLog(@"%@", [test performSelector:@selector(intToString:) withObject:(id)123]);
可是double和struct就不能这样传递了,因为它们占的字节数和指针不一样。如果非要用performSelector的话,就只能修改参数类型为指针了:
- (NSString *)doubleToString:(double *)number {
return [NSString stringWithFormat:@"%f", *number];}double number = 123.456;NSLog(@"%@", [test performSelector:@selector(doubleToString:) withObject:(id)(&number)]);
参数类型算是搞定了,可是要支持多个参数,还得费番气力。理想状态下,我们应该可以实现这2个方法:
@interface NSObject (extend)- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)- (id)performSelector:(SEL)aSelector withParameters:(void *)firstParameter, ...;@end
先看看前者,NSArray要求所有的元素都必须是对象,并且不能为nil,所以适用的范围仍然有限。不过你可别小看它,因为你会发现根本没法用objc_msgSend来实现,因为你在写代码时没法预知参数个数。这时候就轮到NSInvocation登场了:
@implementation NSObject (extend)- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects {
NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:self];
[invocation setSelector:aSelector];
NSUInteger i = 1;
for (id object in objects) {
[invocation setArgument:&object atIndex:++i];
[invocation invoke];
if ([signature methodReturnLength]) {
[invocation getReturnValue:&data];
return}@endNSLog(@"%@", [test performSelector:@selector(combineString:withSecond:withThird:) withObjects:[NSArray arrayWithObjects:@"1", @"2", @"3", nil]]);
这里有3点要注意的:
因为方法调用有self(调用对象)和_cmd(选择器)这2个隐含参数,因此设置参数时,索引应该从2开始。
因为参数是对象,所以必须传递指针,即&object。
methodReturnLength为0时,表明返回类型是void,因此不需要获取返回值。返回值是对象的情况下,不需要我们来创建buffer。但如果是C风格的字符串、数组等类型,就需要自行malloc,并释放内存了。
再来实现第2个方法:
- (id)performSelector:(SEL)aSelector withParameters:(void *)firstParameter, ... {
NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
NSUInteger length = [signature numberOfArguments];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:self];
[invocation setSelector:aSelector];
[invocation setArgument:&firstParameter atIndex:2];
va_list arg_
va_start(arg_ptr, firstParameter);
for (NSUInteger i = 3; i & ++i) {
void *parameter = va_arg(arg_ptr, void *);
[invocation setArgument:&parameter atIndex:i];
va_end(arg_ptr);
[invocation invoke];
if ([signature methodReturnLength]) {
[invocation getReturnValue:&data];
return}NSLog(@"%@", [test performSelector:@selector(combineString:withSecond:withThird:) withParameters:@"1", @"2", @"3"]);NSInteger number1 = 1, number2 = 2, number3 = 3;NSLog(@"%@", [test performSelector:@selector(intsToString:second:third:) withParameters:number1, number2, number3]);
和前面的实现差不多,不过由于参数长度是未知的,所以用到了[signature numberOfArguments]。当然也可以把SEL转成字符串(可用NSStringFromSelector()),然后查找:的数量。处理可变参数时用到了va_start、va_arg和va_end,熟悉C语言的一看就明白了。不过由于不知道参数的类型,所以只能设为void *。而这个程序也报出了警告,说void *和NSInteger类型不兼容。而如果把参数换成double,那就直接报错了。遗憾的是我也不知道怎么判别一个void *指针究竟是指向C数据类型,还是指向一个Objective-C对象,所以最好是封装成Objective-C对象。如果只需要兼容C类型的话,倒是可以将setArgument的参数的&去掉,然后直接传指针进去:
NSInteger number1 = 1, number2 = 2, number3 = 3;NSLog(@"%@", [test performSelector:@selector(intsToString:second:third:) withParameters:&number1, &number2, &number3]);double number4 = 1.0, number5 = 2.0, number6 = 3.0;
NSLog(@"%@", [test performSelector:@selector(doublesToString:second:third:) withParameters:&number4, &number5, &number6]);[test release];
至于NSObject类添加的performSelector:withObject:afterDelay:等方法,也可以用这种方式来支持多个参数。接下来再说说刚才略过的_cmd,它还可以用来实现递归调用。下面就以斐波那契数列为例:
- (NSInteger)fibonacci:(NSInteger)n {
if (n & 2) {
return [self fibonacci:n - 1] + [self fibonacci:n - 2];
return n & 0 ? 1 : 0;}
改成用_cmd实现就变成了这样:
return (NSInteger)[self performSelector:_cmd withObject:(id)(n - 1)] + (NSInteger)[self performSelector:_cmd withObject:(id)(n - 2)];
或者直接用objc_msgSend:
return (NSInteger)objc_msgSend(self, _cmd, n - 1) + (NSInteger)objc_msgSend(self, _cmd, n - 2);
但是每次都通过objc_msgSend来调用显得很费劲,有没有办法直接进行方法调用呢?答案是有的,这就需要用到IMP了。IMP的定义为&id (*IMP) (id, SEL, &)&,也就是一个指向方法的函数指针。NSObject提供methodForSelector:方法来获取IMP,因此只需稍作修改就行了:
- (NSInteger)fibonacci:(NSInteger)n {
static IMP
if (!func) {
func = [self methodForSelector:_cmd];
if (n & 2) {
return (NSInteger)func(self, _cmd, n - 1) + (NSInteger)func(self, _cmd, n - 2);
return n & 0 ? 1 : 0;}
现在运行时间比刚才减少了1/4,还算不错。顺便再展现一下Objective-C强大的动态性,给Test类添加一个sum:and:方法:
NSInteger sum(id self, SEL _cmd, NSInteger number1, NSInteger number2) {
return number1 + number2;}class_addMethod([Test class], @selector(sum:and:), (IMP)sum, "i@:ii");NSLog(@"%d", [test sum:1 and:2]);
class_addMethod的最后那个参数是函数的返回值和参数类型,详细内容可以参考文档。About Objective-CObjective-C is the primary programming language you use when writing software for OS X and iOS. It’s a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime. Objective-C inherits the syntax, primitive types, and flow control statements of C and adds syntax for defining classes and methods. It also adds language-level support for object graph management and object literals while providing dynamic typing and binding, deferring many responsibilities until runtime.At a GlanceThis document introduces the Objective-C language and offers extensive examples of its use. You’ll learn how to create your own classes describing custom objects and see how to work with some of the framework classes provided by Cocoa and Cocoa Touch. Although the framework classes are separate from the language, their use is tightly wound into coding with Objective-C and many language-level features rely on behavior offered by these classes.An App Is Built from a Network of ObjectsWhen building apps for OS X or iOS, you’ll spend most of your time working with objects. Those objects are instances of Objective-C classes, some of which are provided for you by Cocoa or Cocoa Touch and some of which you’ll write yourself.If you’re writing your own class, start by providing a description of the class that details the intended public interface to instances of the class. This interface includes the public properties to encapsulate relevant data, along with a list of methods. Method declarations indicate the messages that an object can receive, and include information about the parameters required whenever the method is called. You’ll also provide a class implementation, which includes the executable code for each method declared in the interface.Relevant Chapters:&, , Categories Extend Existing ClassesRather than creating an entirely new class to provide minor additional capabilities over an existing class, it’s possible to define a category to add custom behavior to an existing class. You can use a category to add methods to any class, including classes for which you don’t have the original implementation source code, such as framework classes like NSString.If you do have the original source code for a class, you can use a class extension to add new properties, or modify the attributes of existing properties. Class extensions are commonly used to hide private behavior for use either within a single source code file, or within the private implementation of a custom framework.Relevant Chapters:&Protocols Define Messaging ContractsThe majority of work in an Objective-C app occurs as a result of objects sending messages to each other. Often, these messages are defined by the methods declared explicitly in a class interface. Sometimes, however, it is useful to be able to define a set of related methods that aren’t tied directly to a specific class.Objective-C uses protocols to define a group of related methods, such as the methods an object might call on its , which are either optional or required. Any class can indicate that it adopts a protocol, which means that it must also provide implementations for all of the required methods in the protocol.Relevant Chapters:&Values and Collections Are Often Represented as Objective-C ObjectsIt’s common in Objective-C to use Cocoa or Cocoa Touch classes to represent values. The NSString class is used for strings of characters, the NSNumber class for different types of numbers such as integer or floating point, and the NSValue class for other values such as C structures. You can also use any of the primitive types defined by the C language, such as int, float or char.Collections are usually represented as instances of one of the collection classes, such as NSArray, NSSet, or NSDictionary, which are each used to collect other Objective-C objects.Relevant Chapters:&Blocks Simplify Common TasksBlocks are a language feature introduced to C, Objective-C and C++ to repr they encapsulate a block of code along with captured state, which makes them similar to closures in other programming languages. Blocks are often used to simplify common tasks such as collection enumeration, sorting and testing. They also make it easy to schedule tasks for concurrent or asynchronous execution using technologies like Grand Central Dispatch (GCD).Relevant Chapters:&Error Objects Are Used for Runtime ProblemsAlthough Objective-C includes syntax for exception handling, Cocoa and Cocoa Touch use exceptions only for programming errors (such as out of bounds array access), which should be fixed before an app is shipped.All other errors—including runtime problems such as running out of disk space or not being able to access a web service—are represented by instances of the NSError class. Your app should plan for errors and decide how best to handle them in order to present the best possible user experience when something goes wrong.Relevant Chapters:&Objective-C Code Follows Established ConventionsWhen writing Objective-C code, you should keep in mind a number of established coding conventions. Method names, for example, start with a lowercase letter and use camel cas for example, doSomething or doSomethingElse. It’s not just the capitalization that’s important, you should also make sure that your code is as readable as possible, which means that method names should be expressive, but not too verbose.In addition, there are a few conventions that are required if you wish to take advantage of language or framework features. Property accessor methods, for example, must follow strict naming conventions in order to work with technologies like
(KVO).Relevant Chapters:&PrerequisitesIf you are new to OS X or iOS development, you should read through
or Start Developing Mac Apps Today before reading this document, to get a general overview of the application development process for iOS and OS X. Additionally, you should become familiar with Xcode before trying to follow the exercises at the end of most chapters in this document. Xcode is the IDE used to build apps for iOS and OS X; you’ll use it to write your code, design your app's user interface, test your application, and debug any problems.Although it’s preferable to have some familiarity with C or one of the C-based languages such as Java or C#, this document does include inline examples of basic C language features such as flow control statements. If you have knowledge of another higher-level programming language, such as Ruby or Python, you should be able to follow the content.Reasonable coverage is given to general object-oriented programming principles, particularly as they apply in the context of Objective-C, but it is assumed that you have at least a minimal familiarity with basic object-oriented concepts. If you’re not familiar with these concepts, you should read the relevant chapters in .See AlsoThe content in this document applies to Xcode 4.4 or later and assumes you are targeting either OS X v10.7 or later, or iOS 5 or later. For more information about Xcode, see . For information on language feature availability, see .Objective-C apps use reference counting to determine the lifetime of objects. For the most part, the Automatic Reference Counting (ARC) feature of the compiler takes care of this for you. If you are unable to take advantage of ARC, or need to convert or maintain legacy code that manages an object’s memory manually, you should read .In addition to the compiler, the Objective-C language uses a runtime system to enable its dynamic and object-oriented features. Although you don’t usually need to worry about how Objective-C “works,” it’s possible to interact directly with this runtime system, as described by
Sending feedback&
We&re sorry, an error has occurred.
Please try submitting your feedback later.
Thank you for providing feedback!
Your input helps improve our developer documentation.
How helpful is this document?
Very helpful
Somewhat helpful
Not helpful
How can we improve this document?
Fix typos or links
Fix incorrect information
Add or update code samples
Add or update illustrations
Add information about...
* Required information
To submit a product bug or enhancement request, please visit the
Please read
before you send us your feedback.}

我要回帖

更多关于 objective c视频教程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信