2011-01-26 54 views
53

Có lẽ điều này sẽ đơn giản đối với hầu hết các bạn, nhưng bạn có thể đưa ra ví dụ về cách tạo các phương thức tương tự (trong mục tiêu-C) và các hàm trong C để tạo các hàm như NSString 's stringWithFormat:, hoặc NSLog()Làm thế nào để tạo các phương thức đối số biến trong Objective-C

Chỉ cần nhắc nhở:

[NSString stringWithFormat:@"example tekst %i %@ %.2f",122,@"sth",3.1415"]; 
NSLog(@"account ID %i email %@",accountID,email); 

tôi muốn tạo ra tương tự như NSString' s phương pháp stringWithFormat:, NSURL - urlWithFormat.

Cảm ơn bạn trước.

Trả lời

115

gì chúng được gọi là, nói chung, là "chức năng variadic" (hoặc các phương pháp, vì nó là) .

Để tạo này, chỉ cần cuối phương pháp declartion của bạn với , ..., như trong

- (void)logMessage:(NSString *)message, ...; 

Tại thời điểm này, bạn có thể muốn quấn nó trong một hàm printf -like, như thực hiện một trong những từ đầu đang cố gắng, tốt nhất.

- (void)logMessage:(NSString *)format, ... { 
    va_list args; 
    va_start(args, format); 
    NSLogv(format, args); 
    va_end(args); 
} 

Lưu ý việc sử dụng NSLogv và không NSLog; xem xét NSLog(NSString *, ...); so với NSLogv(NSString *, va_list); hoặc nếu bạn muốn một chuỗi; initWithFormat:arguments: trên NSString *.


Nếu, mặt khác, bạn không làm việc với chuỗi, mà là một cái gì đó giống như

+ (NSArray *)arrayWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION; 

mọi thứ trở nên dễ dàng hơn rất nhiều.

Trong trường hợp đó, thay vì hàm vprintf kiểu, hãy sử dụng vòng lặp đi qua args, giả sử id khi bạn đi và phân tích cú pháp chúng như bạn thực hiện trong bất kỳ vòng lặp nào.

- (void)logMessage:(NSString *)format, ... { 
    va_list args; 
    va_start(args, format); 

    id arg = nil; 
    while ((arg = va_arg(args,id))) { 
    /// Do your thing with arg here 
    } 

    va_end(args); 
} 

Mẫu cuối cùng này, giả định rằng danh sách va_args không được chấm dứt.

Lưu ý: Để thực hiện việc này, bạn sức mạnh phải bao gồm <stdarg.h>; nhưng nếu bộ nhớ phục vụ, điều này được bao gồm trong kết nối với NSLogv, có nghĩa là nó đi xuống bằng cách "Foundation.h", do đó cũng "AppKit.h" và "Cocoa.h", cũng như một số người khác; vì vậy điều này sẽ làm việc ra khỏi hộp.

+4

Một điều cần lưu ý ở đây là, tham số NSString đầu tiên ở đây có dạng là định dạng và tham số khác được chuyển trong đối số biến. đúng? Vì vậy, trước khi vào vòng lặp for, bạn có một tham số để xử lý. – karim

+0

Tuy nhiên, có thể tránh điều 'chấm dứt' không? ví dụ. nhận được độ dài của các đối số biến? – karim

+0

@karim: Không thể với varargs C để biết số lượng và loại đối số. Các chức năng được gọi là bằng cách nào đó biết các loại và khi nào dừng lại. – newacct

19
- (void)methodWithFormat:(NSString*)format, ... { 
    va_list args; 
    va_start(args,format); 
    //loop, get every next arg by calling va_arg(args,<type>) 
    // e.g. NSString *arg=va_arg(args,NSString*) or int arg=(args,int) 
    va_end(args); 
} 

Nếu bạn muốn vượt qua các đối số biến để stringWithFormat :, sử dụng một cái gì đó như:

NSString *s=[[[NSString alloc] initWithFormat:format arguments:args] autorelease]; 
+1

Phiên bản ARC: NSString * s = [[NSString alloc] initWithFormat: đối số định dạng: args]; – godzilla

8

Một điều cần lưu ý ở đây là, tham số NSString đầu tiên ở đây có dạng là định dạng và tham số còn lại được chuyển trong đối số biến. đúng? Vì vậy, trước khi vào vòng lặp for, bạn có một tham số để xử lý.

- (NSString *) append:(NSString *)list, ... 
{ 
    NSMutableString * res = [NSMutableString string]; 
    [res appendString:list]; 

    va_list args; 
    va_start(args, list); 
    id arg = nil; 

    while((arg = va_arg(args, id))){ 
     [res appendString:arg]; 
    } 
    va_end(args); 
    return res; 
} 

- (void) test_va_arg 
{ 
    NSString * t = [self append:@"a", @"b", @"c", nil]; 
    STAssertEqualObjects(@"abc", t, @""); 
} 
Các vấn đề liên quan