Ry’s Objective-C Tutorial → Data Types---NSString

RyPress - Quality Software Tutorials

You’re reading Ry’s Objective-C Tutorial → Data Types

NSString

As we’ve already seen several times throughout this tutorial, the NSString class is the basic tool for representing text in an Objective-C application. Aside from providing an object-oriented wrapper for strings, NSString provides many powerful methods for searching and manipulating its contents. It also comes with native Unicode support.

Like NSNumber and NSDecimalNumberNSString is an immutable type, so you cannot change it after it’s been instantiated. It does, however, have a mutable counterpart called NSMutableString, which will be discussed at the end of this module.

Creating Strings

The most common way to create strings is using the literal @"Some String" syntax, but the stringWithFormat: class method is also useful for generating strings that are composed of variable values. It takes the same kind of format string as NSLog():

NSString *make = @"Porsche";
NSString *model = @"911";
int year = 1968;
NSString *message = [NSString stringWithFormat:@"That's a %@ %@ from %d!",
                     make, model, year];
NSLog(@"%@", message);

Notice that we used the @"%@" format specifier in the NSLog() call instead of passing the string directly with NSLog(message). Using a literal for the first argument of NSLog() is a best practice, as it sidesteps potential bugs when the string you want to display contains % signs. Think about what would happen when message = @"The tank is 50% full".

NSString provides built-in support for Unicode, which means that you can include UTF-8 characters directly in string literals. For example, you can paste the following into Xcode and use it the same way as any other NSString object.

NSString *make = @"Côte d'Ivoire";

Enumerating Strings

The two most basic NSString methods are length andcharacterAtIndex:, which return the number of characters in the string and the character at a given index, respectively. You probably won’t have to use these methods unless you’re doing low-level string manipulation, but they’re still good to know:

NSString *make = @"Porsche";
for (int i=0; i<[make length]; i++) {
    unichar letter = [make characterAtIndex:i];
    NSLog(@"%d: %hu", i, letter);
}

As you can see, characterAtIndex: has a return type of unichar, which is a typedef for unsigned short. This value represents the Unicode decimal number for the character.

Comparing Strings

String comparisons present the same issues as NSNumber comparisons. Instead of comparing pointers with the == operator, you should always use the isEqualToString: method for a more robust valuecomparison. The following example shows you how this works, along with the useful hasPrefix: and hasSuffix: methods for partial comparisons.

NSString *car = @"Porsche Boxster";
if ([car isEqualToString:@"Porsche Boxster"]) {
    NSLog(@"That car is a Porsche Boxster");
}
if ([car hasPrefix:@"Porsche"]) {
    NSLog(@"That car is a Porsche of some sort");
}
if ([car hasSuffix:@"Carrera"]) {
    // This won't execute
    NSLog(@"That car is a Carrera");
}

And, just like NSNumberNSString has a compare: method that can be useful for alphabetically sorting strings:

NSString *otherCar = @"Ferrari";
NSComparisonResult result = [car compare:otherCar];
if (result == NSOrderedAscending) {
    NSLog(@"The letter 'P' comes before 'F'");
} else if (result == NSOrderedSame) {
    NSLog(@"We're comparing the same string");
} else if (result == NSOrderedDescending) {
    NSLog(@"The letter 'P' comes after 'F'");
}

Note that this is a case-sensitive comparison, so uppercase letters will always be before their lowercase counterparts. If you want to ignore case, you can use the related caseInsensitiveCompare: method.

Combining Strings

The two methods presented below are a way to concatenate NSStringobjects. But, remember that NSString is an immutable type, so these methods actually return a new string and leave the original arguments unchanged.

NSString *make = @"Ferrari";
NSString *model = @"458 Spider";
NSString *car = [make stringByAppendingString:model];
NSLog(@"%@", car);        // Ferrari458 Spider
car = [make stringByAppendingFormat:@" %@", model];
NSLog(@"%@", car);        // Ferrari 458 Spider (note the space)

Searching Strings

NSString’s search methods all return an NSRange struct, which defines a location and a length field. The location is the index of the beginning of the match, and the length is the number of characters in the match. If no match was found, location will contain NSNotFound. For example, the following snippet searches for the Cabrio substring.

NSString *car = @"Maserati GranCabrio";
NSRange searchResult = [car rangeOfString:@"Cabrio"];
if (searchResult.location == NSNotFound) {
    NSLog(@"Search string was not found");
} else {
    NSLog(@"'Cabrio' starts at index %lu and is %lu characters long",
          searchResult.location,        // 13
          searchResult.length);         // 6
}

The next section shows you how to create NSRange structs from scratch.

Subdividing Strings

You can divide an existing string by specifying the first/last index of the desired substring. Again, since NSString is immutable, the following methods return a new object, leaving the original intact.

NSString *car = @"Maserati GranTurismo";
NSLog(@"%@", [car substringToIndex:8]);               // Maserati
NSLog(@"%@", [car substringFromIndex:9]);             // GranTurismo
NSRange range = NSMakeRange(9, 4);
NSLog(@"%@", [car substringWithRange:range]);         // Gran

The global NSMakeRange() method creates an NSRange struct. The first argument specifies the location field, and the second defines the length field. The substringWithRange: method interprets these as the first index of the substring and the number of characters to include, respectively.

It’s also possible to split a string into an NSArray using the componentsSeparatedByString: method, as shown below.

NSString *models = @"Porsche,Ferrari,Maserati";
NSArray *modelsAsArray = [models componentsSeparatedByString:@","];
NSLog(@"%@", [modelsAsArray objectAtIndex:1]);        // Ferrari

Replacing Substrings

Replacing part of a string is just like subdividing a string, except you provide a replacement along with the substring you’re looking for. The following snippet demonstrates the two most common substring replacement methods.

NSString *elise = @"Lotus Elise";
NSRange range = NSMakeRange(6, 5);
NSString *exige = [elise stringByReplacingCharactersInRange:range
                                                 withString:@"Exige"];
NSLog(@"%@", exige);          // Lotus Exige
NSString *evora = [exige stringByReplacingOccurrencesOfString:@"Exige"
                                                   withString:@"Evora"];
NSLog(@"%@", evora);          // Lotus Evora

Changing Case

The NSString class also provides a few convenient methods for changing the case of a string. This can be used to normalize user-submitted values. As with all NSString manipulation methods, these return new strings instead of changing the existing instance.

NSString *car = @"lotUs beSpoKE";
NSLog(@"%@", [car lowercaseString]);      // lotus bespoke
NSLog(@"%@", [car uppercaseString]);      // LOTUS BESPOKE
NSLog(@"%@", [car capitalizedString]);    // Lotus Bespoke

Numerical Conversions

NSString defines several conversion methods for interpreting strings as primitive values. These are occasionally useful for very simple string processing, but you should really consider NSScanner or NSNumberFormatter if you need a robust string-to-number conversion tool.

NSString *year = @"2012";
BOOL asBool = [year boolValue];
int asInt = [year intValue];
NSInteger asInteger = [year integerValue];
long long asLongLong = [year longLongValue];
float asFloat = [year floatValue];
double asDouble = [year doubleValue];

NSMutableString

The NSMutableString class is a mutable version of NSString. Unlike immutable strings, it’s possible to alter individual characters of a mutable string without creating a brand new object. This makes NSMutableString the preferred data structure when you’re performing several small edits on the same string.

NSMutableString inherits from NSString, so aside from the ability to manipulate it in place, you can use a mutable string just like you would an immutable string. That is to say, the API discussed above will still work with an NSMutableString instance, although methods like stringByAppendingString: will still return a NSString object—not an NSMutableString.

The remaining sections present several methods defined by theNSMutableString class. You’ll notice that the fundamental workflow for mutable strings is different than that of immutable ones. Instead of creating a new object and replacing the old value, NSMutableStringmethods operate directly on the existing instance.

Creating Mutable Strings

Mutable strings can be created through the stringWithString: class method, which turns a literal string or an existing NSString object into a mutable one:

NSMutableString *car = [NSMutableString stringWithString:@"Porsche 911"];

After you’ve created a mutable string, the setString: method lets you assign a new value to the instance:

[car setString:@"Porsche Boxster"];

Compare this to NSString, where you re-assign a new value to the variable. With mutable strings, we don’t change the instance reference, but rather manipulate its contents through the mutable API.

Expanding Mutable Strings

NSMutableString provides mutable alternatives to many of theNSString manipulation methods discussed above. Again, the mutable versions don’t need to copy the resulting string into a new memory location and return a new reference to it. Instead, they directly change the existing object’s underlying value.

NSMutableString *car = [NSMutableString stringWithCapacity:20];
NSString *model = @"458 Spider";

[car setString:@"Ferrari"];
[car appendString:model];
NSLog(@"%@", car);                    // Ferrari458 Spider

[car setString:@"Ferrari"];
[car appendFormat:@" %@", model];
NSLog(@"%@", car);                    // Ferrari 458 Spider

[car setString:@"Ferrari Spider"];
[car insertString:@"458 " atIndex:8];
NSLog(@"%@", car);                    // Ferrari 458 Spider

Also note that, like any well-designed Objective-C class, the method names of NSString and NSMutableString reflect exactly what they do. The former creates and returns a brand new string, so it uses names like stringByAppendingString:. On the other hand, the latter operates on the object itself, so it uses verbs like appendString:.

Replacing/Deleting Substrings

It’s possible to replace or delete substrings via thereplaceCharactersInRange:withString: anddeleteCharactersInRange: methods, as shown below.

NSMutableString *car = [NSMutableString stringWithCapacity:20];
[car setString:@"Lotus Elise"];
[car replaceCharactersInRange:NSMakeRange(6, 5)
                   withString:@"Exige"];
NSLog(@"%@", car);                               // Lotus Exige
[car deleteCharactersInRange:NSMakeRange(5, 6)];
NSLog(@"%@", car);                               // Lotus

When To Use Mutable Strings

Since NSString and NSMutableString provide such similar functionality, it can be hard to know when to use one over the other. In general, the static nature of NSString makes it more efficient for most tasks; however, the fact that an immutable string can’t be changed without generating a new object makes it less than ideal when you’re trying to perform several small edits.

The two examples presented in this section demonstrate the advantages of mutable strings. First, let’s take a look at an anti-pattern for immutable strings. The following loop generates a string containing all of the numbers between 0 and 999 using NSString.

// DO NOT DO THIS. EVER.
NSString *indices = @"";
for (int i=0; i<1000; i++) {
    indices = [indices stringByAppendingFormat:@"%d", i];
}

Remember that stringByAppendingFormat: creates a new NSStringinstance, which means that in each iteration, the entire string gets copied to a new block of memory. The above code allocates 999 string objects that serve only as intermediary values, resulting in an application that requires a whopping 1.76 MB of memory. Needless to say, this is incredibly inefficient.

Now, let’s take a look at the mutable version of this snippet:

NSMutableString *indices = [NSMutableString stringWithCapacity:1];
for (int i=0; i<1000; i++) {
    [indices appendFormat:@"%d", i];
}

Since mutable strings manipulate their contents in place, no copying is involved, and we completely avoid the 999 unnecessary allocations. Internally, the mutable string’s storage dynamically expands to accommodate longer values. This reduces the memory footprint to around 19 KB, which is much more reasonable.

So, a good rule of thumb is to use a mutable string whenever you’re running any kind of algorithm that edits or assembles a string in several passes and to use an immutable string for everything else. This also applies to setsarrays, and dictionaries.

Mailing List

Sign up for my low-volume mailing list to find out when new content is released. Next up is a comprehensive Swift tutorial planned for late January.

Email Address:

You’ll only receive emails when new tutorials are released, and your contact information will never be shared with third parties. Click here to unsubscribe.

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值