Reputation: 804
I have tried many things already, changing up a few things wrote in Swift differently, alternatively using a for instead of the built in 'contains' in swift to see if that might be the problem but Objective-C was still faster.
Objective-C code runs at about - 0.035266s. Swift - around 0.987877011299133s.
Can you guys help me find out what might be wrong with the code? I tried to write both codes identical line for line as much as it was possible, or used the languages given substitutes.
Swift main:
import Foundation
let startDate = NSDate();
let cc = CaesarCipher();
let path = "/Users/Jay/Documents/Projects/CaesarCipher/CaesarCipherSwift/data.txt"
var content = String(contentsOfFile:path, encoding: NSUTF8StringEncoding, error: nil)
content = content!.lowercaseString;
let arr = cc.cipher(content!, shift: 13);
let endDate = NSDate();
let time = NSTimeInterval(endDate .timeIntervalSinceDate(startDate));
println("ciphered text: \n \(arr) \n");
println("execution time: \n \(time) \n");
Swift CaeserCipher:
import Foundation
class CaesarCipher
{
let alphabet: [Character];
var textToCipher: String;
var shift: Int;
init(){
self.alphabet = ["a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z"];
self.textToCipher = String();
self.shift = Int();
}
func cipher(textToCipher: String, shift: Int)->String{
self.textToCipher = textToCipher;
self.shift = shift;
var newArray: [Character] = [];
for letter in self.textToCipher{
if(contains(alphabet, letter))
{
var modValue = self.shift % 26;
var indexOfLetter = find(alphabet, letter)!;
if(modValue > indexOfLetter){
modValue = modValue-indexOfLetter;
newArray.append(alphabet[alphabet.count-modValue]);
}else{
newArray.append(alphabet[indexOfLetter-modValue]);
}
}else{
newArray.append(" ");
}
}
return String(newArray);
}
}
Objective-C main:
#import <Foundation/Foundation.h>
#import "CaesarCipher.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSDate *methodStart = [NSDate date];
CaesarCipher *cc = [[CaesarCipher alloc] init];
NSString *path = @"/Users/Jay/Documents/Projects/CaesarCipher/CaesarCipherObjectiveC/data.txt";
NSString *textToCipher =
[[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil] lowercaseString];
NSString *cipherText = [cc cipher:textToCipher :13];
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(@"%@", cipherText);
NSLog(@"executionTime = %f", executionTime);
}
return 0;
}
Objective-C CaeserCipher.m:
#import <Foundation/Foundation.h>
#import "CaesarCipher.h"
@implementation CaesarCipher
{
NSArray *alphabet;
NSMutableArray *cipherTextArray;
}
-(id)init{
self = [super init];
if(self){
alphabet = [NSArray arrayWithObjects:@"a", @"b", @"c", @"d", @"e", @"f", @"g",
@"h", @"i", @"j", @"k", @"l", @"m", @"n", @"o", @"p", @"q", @"r", @"s",
@"t", @"u", @"v", @"w", @"x", @"y", @"z", nil];
}
return self;
}
-(NSString *)cipher:(NSString *)textToCipher :(int)shift
{
NSMutableString *text;
text = [NSMutableString string];
for(int i=0; i<textToCipher.length; i++){
NSString *currentLetter =
[NSString stringWithFormat:@"%c", [textToCipher characterAtIndex:i]];
if([alphabet containsObject:currentLetter]){
int modValue = shift % 26;
int indexOfLetter = (int)[alphabet indexOfObject:currentLetter];
if(modValue > indexOfLetter){
modValue = modValue - indexOfLetter;
[text appendString:[alphabet objectAtIndex:(alphabet.count-modValue)]];
}else{
[text appendString:[alphabet objectAtIndex:(indexOfLetter-modValue)]];
}
}else{
[text appendString:@" "];
}
}
return text;
}
@end
Objective-C CaeserCipher.h:
@interface CaesarCipher: NSObject
@property int numerator, denominator;
@property NSString *str;
-(NSString *) cipher: (NSString *) textToCipher: (int) shift;
@end
Upvotes: 1
Views: 196
Reputation: 70098
This test is a combination of Swift language + Swift standard library against a combination of Objective-C language + Cocoa library.
Let's try with Swift language + Swift standard library against Swift language + Cocoa library:
class SWCaesarCipher { // same code as yours, but with Cocoa methods instead of Swift standard library ones
let alphabet: NSArray
var textToCipher: NSString
var shift: Int
init(){
self.alphabet = NSArray(objects: "a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z")
self.textToCipher = NSString()
self.shift = Int()
}
func cipher(textToCipher: NSString, shift: Int) -> NSString {
self.textToCipher = textToCipher
self.shift = shift
var text = NSMutableString()
var i = 0
while i < self.textToCipher.length {
var letter = NSString(format: "%c", textToCipher.characterAtIndex(i))
if alphabet.containsObject(letter) {
var modValue = self.shift % 26
var indexOfLetter = alphabet.indexOfObject(letter)
if (modValue > indexOfLetter) {
modValue = modValue - indexOfLetter
text.appendString(alphabet.objectAtIndex(alphabet.count - modValue) as! String)
}else{
text.appendString(alphabet.objectAtIndex(indexOfLetter-modValue) as! String)
}
}else{
text.appendString(" ")
}
i++
}
return text
}
}
var startDate = NSDate()
let cc = SWCaesarCipher()
var content = NSString(string: "Black malt berliner weisse, filter. Ibu degrees plato alcohol. ipa hard cider ester infusion conditioning tank. Dry stout bottom fermenting yeast wort chiller wort chiller lager hand pump ! All-malt dunkle bright beer grainy, original gravity wheat beer glass.")
content = content.lowercaseString
let arr = cc.cipher(content, shift: 13)
var endDate = NSDate()
var time = NSTimeInterval(endDate .timeIntervalSinceDate(startDate))
println("ciphered text: \n \(arr) \n")
println("execution time: \n \(time) \n")
// your original code
class OPCaesarCipher
{
let alphabet: [Character];
var textToCipher: String;
var shift: Int;
init(){
self.alphabet = ["a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z"];
self.textToCipher = String();
self.shift = Int();
}
func cipher(textToCipher: String, shift: Int)->String{
self.textToCipher = textToCipher;
self.shift = shift;
var newArray: [Character] = [];
for letter in self.textToCipher{
if(contains(alphabet, letter))
{
var modValue = self.shift % 26;
var indexOfLetter = find(alphabet, letter)!;
if(modValue > indexOfLetter){
modValue = modValue-indexOfLetter;
newArray.append(alphabet[alphabet.count-modValue]);
}else{
newArray.append(alphabet[indexOfLetter-modValue]);
}
}else{
newArray.append(" ");
}
}
return String(newArray);
}
}
let startDate2 = NSDate();
let op = OPCaesarCipher();
var content2 = "Black malt berliner weisse, filter. Ibu degrees plato alcohol. ipa hard cider ester infusion conditioning tank. Dry stout bottom fermenting yeast wort chiller wort chiller lager hand pump ! All-malt dunkle bright beer grainy, original gravity wheat beer glass."
content2 = content2.lowercaseString
let arr2 = op.cipher(content2, shift: 13)
let endDate2 = NSDate();
let time2 = NSTimeInterval(endDate2.timeIntervalSinceDate(startDate2));
println("ciphered text: \n \(arr2) \n");
println("execution time: \n \(time2) \n");
I kept the same code example as yours, except I've used the same objects as you do in Objective-C: NSMutableString
, etc.
Your example: 1.24008899927139
New version: 0.687016010284424
So I guess the library we're using to manipulate objects is as much important as the language, in our case.
Still, technically, yes, it appears that an "all Swift" solution is roughly 2x slower than a Swift + Cocoa solution (which should be roughly the same than Objective-C + Cocoa when compiled with equivalent options, IIRC).
Upvotes: 1
Reputation: 131418
I was curious about Swift performance vs Objective-C and so I wrote a program to compare the two.
You can read about it here:
Testing Swift's performance against C/Objective-C
It turns out that Swift code performs pretty poorly with compiler optimization turned off (which is the standard setting for debug builds.) You really need to switch to release build in order to see what your code is going to perform like in the app store.
I don't recommend changing the compiler settings for debug builds because if you do that source debugging becomes difficult. (The compiler can optimize away local variables, it can change the order of execution or blend multiple source lines into one, etc.)
Try creating a build scheme that builds a release build and time THAT. I bet you'll find it runs much faster.
You can also switch the build settings on the release build to turn off bounds checking on arrays. That speeds things up, but it's kinda dangerous, and makes debugging harder.
Upvotes: 3