mcfly soft
mcfly soft

Reputation: 11645

Performance with a lot of string operations comparing Objective-C and Swift

I have a lot of string operations like concatenating, replacing, finding indexes of large texts (10000 characters) ...

The operations are too slow. Exactly the same doing in Java/Android is faster.

I am asking if the same in Objective-C is faster.

I am a iOS newby and only know Swift so far (so I can't try simply), thats why I asking if Objective-C with swift-bridging could be faster?

Update I have a lot of substring operations in a loop (also replace), which concatenates a new String. NewText & sText are of Type String, sText has about 10000 characters, the loop will have about 100 iterations:

NewText=NewText + sText.substring(istart,endIndex: iend);

func substring(startIndex: Int, endIndex: Int) -> String
{
    //println("substring" + self);
    var start = advance(self.startIndex, startIndex)
    var end = advance(self.startIndex, endIndex)
    return self.substringWithRange(Range<String.Index>(start: start, end: end))
}

UPDATE 2 Performance Test (replace string) with String, NSString, CFString

From the information you all provided, it seems not to be a difference between Objective-C and Swift. It is more which Stringtype to use. I made a performance test with the Types: String, NSString and CFString

 func performance_test_with_strings(){

    var sTextNSString:NSString="<1000 character> searchstring end";

    var sTextString=String(sTextNSString);
    //var sTextCFString:CFMuString=sTextNSString as CFString;
    var stoReplace="searchstring";

    var sTextCFString:CFMutableStringRef=CFStringCreateMutable(nil, 0);
    CFStringAppend(sTextCFString, sTextString as! CFMutableStringRef);
    var stoReplaceCFString="searchstring" as CFString;
    var stoReplaceCFString2="mynewstring" as CFString;
    var chrono1:Chronometer=Chronometer();
    chrono1.start();

    for var i=0;i<10000;i++ {
        var newText=sTextNSString.stringByReplacingOccurrencesOfString(stoReplace, withString: "mynewstring");
    }
    chrono1.zwischenstand("after replacing with a NSString");

    for var i=0;i<10000;i++ {
        var newText=sTextString.stringByReplacingOccurrencesOfString(stoReplace, withString: "mynewstring");
    }
    chrono1.zwischenstand("after replacing with a String");
    //CFShow(cfmutablestring);

    for var i=0;i<5000;i++ {
        // To compare this correct I'll have to do 2 replacments in a loop of only 5000 iterations

        specialreplace(&sTextCFString,sWhat: "searchstring",sTo: "mynewstring");
        specialreplace(&sTextCFString,sWhat: "mynewstring",sTo: "searchstring");
    }
    chrono1.zwischenstand("after replacing with a CFString");
    chrono1.showMeasures();
    exit(0);
}

func specialreplace(inout sText:CFMutableStringRef,sWhat:String, sTo:String){

    var cfRange = CFStringFind(sText, sWhat as CFString, nil);
    CFStringReplace(sText, cfRange, sTo as CFString);
}

class Chronometer: NSObject {

    var mearures:[(String,Double)]=[(String,Double)]();

    var starttime = NSDate();   // <<<<<<<<<<   end time
    var lasttime:Double=0;

    func start(){
        starttime = NSDate();   // <<<<<<<<<<   end time
    }
    func zwischenstand(mytext:String){
        var zwischenzeit = NSDate();
        let timeInterval: Double = zwischenzeit.timeIntervalSinceDate(starttime);
        let actualtimeconsumed=timeInterval-lasttime;
        mearures.append((mytext,actualtimeconsumed));
        var textshow=mytext + " actual : " + String(stringInterpolationSegment: actualtimeconsumed);
        textshow=textshow + " total :" + String(stringInterpolationSegment: timeInterval);
        println(textshow);
        lasttime=timeInterval;
    }

    func showMeasures(){
        var total:Double=0;
        for var i=0 ; i < mearures.count ; i++ {
            let text=mearures[i].0;
            let measure=mearures[i].1;
            println(text + " : " + String(stringInterpolationSegment: measure));
            total = total + measure;
        }
        println("total : " + String(stringInterpolationSegment: total));
    }
}

after replacing with a NSString actual : 1.15460801124573 total :1.15460801124573

after replacing with a String actual : 1.15148597955704 total :2.30609399080276

after replacing with a CFString actual : 0.323610007762909 total :2.62970399856567

after replacing with a NSString : 1.15460801124573

after replacing with a String : 1.15148597955704

after replacing with a CFString : 0.323610007762909

total : 2.62970399856567

So my conclusion for my case its the best to use CFString.

Is this test correct?

Upvotes: 2

Views: 1823

Answers (2)

JeremyP
JeremyP

Reputation: 86651

One thing to note about Swift is that it attempts to do Unicode handling properly. Java and Cocoa's NSString do not do this. They both assume that the string is encoded in UTF-16 and each character only takes one 16 bit integer. Therefore string handling only works properly for what is called the Basic Multilingual Plane

With NSString and in Java, finding the nth "character" is easy, you just index to the nth item in the array, but that could easily be the second part of a surrogate pair. You also can't tell if that really is the nth character except by scanning all the previous characters to make sure none of them are two word characters.

Swift does this properly, but at the expense of a lot of linear (aka slow) scanning through strings.

Upvotes: 3

lead_the_zeppelin
lead_the_zeppelin

Reputation: 2052

I would use Core Foundation's CFMutableString operations. I generally tend to find them much faster than their Cocoa variants.

Upvotes: 1

Related Questions