質問

必要があります。を新規作成 NSStringからフォーマット文字列のような@xxx=%@,yyy=%@"、NSArray物?

のNSSTringクラスがいくつかの方法のように:

- (id)initWithFormat:(NSString *)format arguments:(va_list)argList
- (id)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList
+ (id)stringWithFormat:(NSString *)format, ...

にもかNSArrayとして引数として選んだリアルの使い方を創造するva_listからNSArray...

役に立ちましたか?

解決

NSArrayのからのva_listを作成するために、実際には難しいことではありません。件名にマット・ギャラガーの優れた記事を参照してください。

ここであなたが欲しいものを行うにはNSStringのカテゴリがあります:

@interface NSString (NSArrayFormatExtension)

+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments;

@end

@implementation NSString (NSArrayFormatExtension)

+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments
{
    char *argList = (char *)malloc(sizeof(NSString *) * arguments.count);
    [arguments getObjects:(id *)argList];
    NSString* result = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
    free(argList);
    return result;
}

@end

するとます:

NSString* s = [NSString stringWithFormat:@"xxx=%@, yyy=%@" array:@[@"XXX", @"YYY"]];
NSLog( @"%@", s );

残念ながら、64ビットのため、va_listのフォーマットが変わっていないので、上記のコードは、もはや機能します。そして、おそらくそれは明らかに変更される場合があります形式に依存与えとにかく使用すべきではありません。 va_listのを作成するために、何の本当に堅牢な方法がありません考えると、よりよい解決策は、単に合理的な最大値に引数の数を制限(10言う)し、最初の10個の引数でstringWithFormatを呼び出すことで、このような何かます:

+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments
{
    if ( arguments.count > 10 ) {
        @throw [NSException exceptionWithName:NSRangeException reason:@"Maximum of 10 arguments allowed" userInfo:@{@"collection": arguments}];
    }
    NSArray* a = [arguments arrayByAddingObjectsFromArray:@[@"X",@"X",@"X",@"X",@"X",@"X",@"X",@"X",@"X",@"X"]];
    return [NSString stringWithFormat:format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9] ];
}

他のヒント

自動参照カウント(ARC)を使用して、この回答に基づいて: https://stackoverflow.com/a/8217755/881197

以下の方法でNSStringするカテゴリを追加します。

+ (id)stringWithFormat:(NSString *)format array:(NSArray *)arguments
{
    NSRange range = NSMakeRange(0, [arguments count]);
    NSMutableData *data = [NSMutableData dataWithLength:sizeof(id) * [arguments count]];
    [arguments getObjects:(__unsafe_unretained id *)data.mutableBytes range:range];
    NSString *result = [[NSString alloc] initWithFormat:format arguments:data.mutableBytes];
    return result;
}

私の頭に浮かんだ一つの解決策は、私のような引数の固定多数で動作メソッドを作成することができることです

+ (NSString *) stringWithFormat: (NSString *) format arguments: (NSArray *) arguments {
    return [NSString stringWithFormat: format ,
          (arguments.count>0) ? [arguments objectAtIndex: 0]: nil,
          (arguments.count>1) ? [arguments objectAtIndex: 1]: nil,
          (arguments.count>2) ? [arguments objectAtIndex: 2]: nil,
          ...
          (arguments.count>20) ? [arguments objectAtIndex: 20]: nil];
}

私はまた、フォーマット文字列を超える21「%」文字を持っているかどうかを確認し、その場合には例外をスローするためのチェックを追加することができます。

の@Chuck のあなたはhref="https://stackoverflow.com/questions/431910/">は可変引数のにNSArrayのを変換することはできません%@を検索し、それを毎回交換することはお勧めしません。ここで(。文字列の途中で文字を交換すると、あなたは別の方法で同じことを達成することができた場合、一般的には非常に非効率的ではなく、良いアイデアです)、あなたが記述している形式の文字列を作成するためのより効率的な方法です。

NSArray *array = ...
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
    [newArray addObject:[NSString stringWithFormat:@"x=%@", [object description]]];
}
NSString *composedString = [[newArray componentsJoinedByString:@", "] retain];
[pool drain];

私は自動解放文字列は各アレイ・エントリのために作成されるので、良好なハウスキーピングのための自動解放プールが含まれており、可変配列は、同様に自動解放されます。あなたは簡単にメソッド/関数にこれを作り、それを保持せずにcomposedStringを返し、必要に応じてコードの別の場所で自動解放を扱うことができます。

この答えはバグがあります。述べたように、新しいプラットフォームが「10要素アレイ」方法を使用するよりも他の導入されたときに動作することが保証され、この問題に対する解決策は存在しない。

<時間> 私は64ビットアーキテクチャでコンパイルすることを行ったまで

solidsunによって答えが、うまく働いていました。これは、エラーの原因となった。

EXC_BAD_ADDRESSタイプEXC_I386_GPFLT

溶液は、メソッドに引数リストを渡すためのわずかに異なるアプローチを使用していました

+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments;
{
     __unsafe_unretained id  * argList = (__unsafe_unretained id  *) calloc(1UL, sizeof(id) * arguments.count);
    for (NSInteger i = 0; i < arguments.count; i++) {
        argList[i] = arguments[i];
    }

    NSString* result = [[NSString alloc] initWithFormat:format, *argList] ;//  arguments:(void *) argList];
    free (argList);
    return result;
}

の単一の要素を持つ配列の場合のみ有効です。

がありなしです一般的な方法は、可変引数を使用して関数またはメソッドに配列を渡すを。以下のようなものを使用して、それを、この特定のケースでは、しかし、あなたは可能性が偽物ます:

for (NSString *currentReplacement in array)
    [string stringByReplacingCharactersInRange:[string rangeOfString:@"%@"] 
            withString:currentReplacement];

EDIT:受け入れられた答えがこれを行う方法があると主張し、関係なく、この答えは見えるかもしれませんがどのように壊れやすいの、そのアプローチは、はるかに脆弱です。それは同じままことが保証されていない実装定義挙動(va_listの具体的構造)に依存しています。私は私の答えが正しいか、それが唯一の言語やフレームワークの定義された機能に依存しているので、私の提案された解決策が壊れにくくであることを維持します。

は、スウィフトのソリューションを必要とする人のために、ここでスウィフトでこれを行うための拡張機能です。

extension String {

    static func stringWithFormat(format: String, argumentsArray: Array<AnyObject>) -> String {
        let arguments = argumentsArray.map { $0 as! CVarArgType }
        let result = String(format:format, arguments:arguments)
        return result
    }

}

はい、それは可能です。

:あなたはそれを埋めるためにNSArrayを伝え、その後、va_listsのいずれかを行いますので、マックOS XをターゲットにGCCで、少なくとも、idは、単にCの配列です
NSArray *argsArray = [[NSProcessInfo processInfo] arguments];
va_list args = malloc(sizeof(id) * [argsArray count]);
NSAssert1(args != nil, @"Couldn't allocate array for %u arguments", [argsArray count]);

[argsArray getObjects:(id *)args];

//Example: NSLogv is the version of NSLog that takes a va_list instead of separate arguments.
NSString *formatSpecifier = @"\n%@";
NSString *format = [@"Arguments:" stringByAppendingString:[formatSpecifier stringByPaddingToLength:[argsArray count] * 3U withString:formatSpecifier startingAtIndex:0U]];
NSLogv(format, args);

free(args);

あなたは、ポータブルでなければなりませんコードでこの性質に依存すべきではありません。 iPhoneの開発者は、これはあなたは間違いなく、デバイス上でテストする必要があります一つのことです。

- (NSString *)stringWithFormat:(NSString *)format andArguments:(NSArray *)arguments {
    NSMutableString *result = [NSMutableString new];
    NSArray *components = format ? [format componentsSeparatedByString:@"%@"] : @[@""];
    NSUInteger argumentsCount = [arguments count];
    NSUInteger componentsCount = [components count] - 1;
    NSUInteger iterationCount = argumentsCount < componentsCount ? argumentsCount : componentsCount;
    for (NSUInteger i = 0; i < iterationCount; i++) {
        [result appendFormat:@"%@%@", components[i], arguments[i]];
    }
    [result appendString:[components lastObject]];
    return iterationCount == 0 ? [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : result;
}

の形式と引数でテストされてます:

NSString *format = @"xxx=%@, yyy=%@ last component";
NSArray *arguments = @[@"XXX", @"YYY", @"ZZZ"];

結果:XXX = XXX、YYY = YYY最後の成分

NSString *format = @"xxx=%@, yyy=%@ last component";
NSArray *arguments = @[@"XXX", @"YYY"];

結果:XXX = XXX、YYY = YYY最後の成分

NSString *format = @"xxx=%@, yyy=%@ last component";
NSArray *arguments = @[@"XXX"];

結果:XXX = XXX最後のコンポーネント

NSString *format = @"xxx=%@, yyy=%@ last component";
NSArray *arguments = @[];

結果:最後のコンポーネント

NSString *format = @"some text";
NSArray *arguments = @[@"XXX", @"YYY", @"ZZZ"];

結果:いくつかのテキスト

私は、これはしかし、私はそれを自分自身を行うために管理していないことが可能であることを主張し、ウェブ上でいくつかのコードを見つけ、あなたが事前に引数の数がわからない場合は、しかし、あなたはまた、動的ので、フォーマット文字列を構築する必要があります私はポイントが表示されません。

あなただけの配列を繰り返すことによって、文字列を構築する。ほう

あなたはstringByAppendingStringを見つけるかもしれない:またはstringByAppendingFormat:インスタンスメソッド便利な

で作成カテゴリNSStringという機能を受けるフォーマット配列を返します文字列の置換オブジェクト。

@interface NSString (NSArrayFormat)

+ (NSString *)stringWithFormat:(NSString *)format arrayArguments:(NSArray *)arrayArguments;

@end

@implementation NSString (NSArrayFormat)

+ (NSString *)stringWithFormat:(NSString *)format arrayArguments:(NSArray *)arrayArguments {
    static NSString *objectSpecifier = @"%@"; // static is redundant because compiler will optimize this string to have same address
    NSMutableString *string = [[NSMutableString alloc] init]; // here we'll create the string
    NSRange searchRange = NSMakeRange(0, [format length]);
    NSRange rangeOfPlaceholder = NSMakeRange(NSNotFound, 0); // variables are declared here because they're needed for NSAsserts
    NSUInteger index;
    for (index = 0; index < [arrayArguments count]; ++index) {
        rangeOfPlaceholder = [format rangeOfString:objectSpecifier options:0 range:searchRange]; // find next object specifier
        if (rangeOfPlaceholder.location != NSNotFound) { // if we found one
            NSRange substringRange = NSMakeRange(searchRange.location, rangeOfPlaceholder.location - searchRange.location);
            NSString *formatSubstring = [format substringWithRange:substringRange];
            [string appendString:formatSubstring]; // copy the format from previous specifier up to this one
            NSObject *object = [arrayArguments objectAtIndex:index];
            NSString *objectDescription = [object description]; // convert object into string
            [string appendString:objectDescription];
            searchRange.location = rangeOfPlaceholder.location + [objectSpecifier length]; // update the search range in order to minimize search
            searchRange.length = [format length] - searchRange.location;
        } else {
            break;
        }
    }
    if (rangeOfPlaceholder.location != NSNotFound) { // we need to check if format still specifiers
        rangeOfPlaceholder = [format rangeOfString:@"%@" options:0 range:searchRange];
    }
    NSAssert(rangeOfPlaceholder.location == NSNotFound, @"arrayArguments doesn't have enough objects to fill specified format");
    NSAssert(index == [arrayArguments count], @"Objects starting with index %lu from arrayArguments have been ignored because there aren't enough object specifiers!", index);
    return string;
}

@end

でNSArrayを作成し実行時に対応できませんのでコンパイル時の警報が利用できまNSAssertにお申し付け下さいませた場合の数指示子では等しいとのオブジェクト数内の配列になります。

プロジェクト Githubこのカテゴリーも見つけることができます。も追加されたチャックのバージョンを用いたstringByReplacingCharactersInRange:'プラスである。

一万オブジェクトを配列には、バージョンの"stringByReplacingCharactersInRange:'しない規模のもの(待機で約2分後にのっていない。のバージョンNSMutableString、関数の文字列は約4秒です。この試験を利用したシミュレーション。 ご利用になる前に、試験すべき実デバイス用装置のときには欠かすことのできないスペック).

編集:IPhone5sのバージョンNSMutableStringか10.471655s(百万円)iPhone5か21.304876。

ここで答えが明示的に配列を作成せずにいます:

   NSString *formattedString = [NSString stringWithFormat:@"%@ World, Nice %@", @"Hello", @"Day"];

最初の文字列をフォーマットするターゲット文字列であり、次の文字列は、ターゲットに挿入される文字列です。

いいえ、あなたがすることはできません。可変引数呼び出しは、コンパイル時に解決し、あなたのNSArrayのは、実行時にのみコンテンツを持っている。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top