1. Trang chủ
  2. » Công Nghệ Thông Tin

iOS 5 Programming Cookbook phần 2 docx

89 731 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 89
Dung lượng 3,67 MB

Nội dung

NSLog(@"Array = %@", array); if ([array respondsToSelector:@selector(sortUsingComparator:)]){ /* Use the sortUsingComparator: instance method of the array to sort it */ } else if ([array respondsToSelector:@selector(sortUsingFunction:context:)]){ /* Use the sortUsingFunction:context: instance method of the array to sort */ } else { /* Do something else */ } Fantastic. We checked the existence of instance methods. How about class methods? The NSArray class again has various class methods, two of which are the arrayWithOb jects: and the arrayWithObjects:count: methods. We can determine their availability at run-time and use them to initialize the array: NSArray *array = nil; if ([NSArray respondsToSelector:@selector(arrayWithObjects:count:)]){ NSString *strings[4]; strings[0] = @"String 1"; strings[1] = @"String 2"; strings[2] = @"String 3"; strings[3] = @"String 4"; array = [NSArray arrayWithObjects:strings count:4]; } else if ([NSArray respondsToSelector:@selector(arrayWithObjects:)]){ array = [NSArray arrayWithObjects: @"String 1", @"String 2", @"String 3", @"String 4", nil]; } else { /* Do something else */ } NSLog(@"Array = %@", array); See Also XXX 1.19 Determining Whether Instance or Class Methods are Available | 73 1.20 Determining Whether a Class is Available at Run Time Problem You are using a few classes that are available in the latest SDK but you are unsure whether they are available on devices that will be running your app, because your deployment target is earlier than the latest SDK. Solution Use the NSClassFromString function. Pass the name of your class to this method as a string. If the return value of this function is nil, that class is not available on the device that runs your app; otherwise, that class is available on the device and you can go ahead and use it as you wish. Here is an example: if (NSClassFromString(@"NSJSONSerialization") != nil){ /* You can use this class */ [NSJSONSerialization JSONObjectWithData: /* Put data here */ options: /* Put options here */ error: ]; /* Handle errors here */ } else { /* That class is not available */ } Discussion It's no secret that users are slow in upgrading their operating systems. Working for various companies, I can confirm that usually around 30% of iOS devices today are running iOS versions that are about a year or a year and a half old. If today we are working with iOS 5, there are still iOS devices out there running iOS, 3 for instance. Revenue for developers is important, so we need to make sure that we do support older devices to some extent to be able to create a bigger user-base than by pushing an app that only runs on iOS 5 out to the App Store. Some of the classes that we use are available only on specific versions of iOS. For in- stance, the NSJSONSerialization class is available only in iOS 5 SDK and only devices running iOS 5 will be able to run such code. However, if you are planning to support iOS 4 as well as iOS 5, then you can, at run-time, detect the availability of the afore- mentioned class using the NSClassFromString function, and pass the name of the class that you want to use as a parameter to this function. If the return value of this function is nil, that means the class that you specified cannot be instantiated on the specific device running your app. In this situation, you will need to choose an alternative path and instantiate another class that is available on the device, which carries out similar functionalities as the absent class. 74 | Chapter 1: The Basics See Also XXX 1.21 Allocating and Making Use of Strings Problem You want work with strings in Objective-C Solution Use NSString and NSMutableString classes. Discussion The NSString and NSMutableString classes allow you to store a string of characters in memory. The NSString class is immutable, meaning that once it is created, its contents cannot be modified. Mutable strings represented with the NSMutableString can be modified once they are created. We will see an example of both of these classes very soon. Objective-C strings should be placed inside double quotes. The starting double-quote should be prefixed with an at sign (@). For instance, the sentence Hello, World, rep- resented as a string in Objective-C, is written like so: @"Hello, World" There are various ways of placing a string inside an instance of NSString or NSMutable String classes. Here is how: NSString *simpleString = @"This is a simple string"; NSString *anotherString = [NSString stringWithString:@"This is another simple string"]; NSString *oneMorestring = [[NSString alloc] initWithString:@"One more!"]; NSMutableString *mutableOne = [NSMutableString stringWithString:@"Mutable String"]; NSMutableString *anotherMutableOne = [[NSMutableString alloc] initWithString:@"A retained one"]; NSMutableString *thirdMutableOne = [NSMutableString stringWithString:simpleString]; If you are working with strings, you are probably going to need the length of your string objects from time to time to make specific decisions at runtime. Imagine this scenario: you have asked your user to enter her name in a text field. When she presses the button 1.21 Allocating and Making Use of Strings | 75 to confirm her name, you would need to check whether she has in fact entered her name. You can do this by calling the length method on an instance of NSString or any of its subclasses, including NSMutableString, as shown here: NSString *userName = ; if ([userName length] == 0){ /* The user didn't enter her name */ } else { /* The user did in face enter her name */ } Another thing that you might want to know about strings is how you to convert a string to its equivalent integral value, i.e., converting a string to an integer, float, or double. You can use the integerValue, floatValue, and doubleValue methods of NSString (or any of its subclasses) to retrieve the integer, float and double values of a string, like so: NSString *simpleString = @"123.456"; NSInteger integerOfString = [simpleString integerValue]; NSLog(@"integerOfString = %ld", (long)integerOfString); CGFloat floatOfString = [simpleString floatValue]; NSLog(@"floatOfString = %f", floatOfString); double doubleOfString = [simpleString doubleValue]; NSLog(@"doubleOfString = %f", doubleOfString); The output of this code is: integerOfString = 123 floatOfString = 123.456001 doubleOfString = 123.456000 If you would like to work with C Strings, you can! You will use them like NSString without the leading at-sign, like so: char *cString = "This is a C String"; If you want to convert an NSString to a C String, you must use the UTF8String method of NSString, like so: const char *cString = [@"Objective-C String" UTF8String]; NSLog(@"cString = %s", cString); You can use the %s format specifier to print a C String out to the console,. In comparison, use the %@ format specifier to print out NSString objects. To convert a C String to NSString, you must use the stringWithUTF8String: method of the NSString class, as demonstrated here: 76 | Chapter 1: The Basics NSString *objectString = [NSString stringWithUTF8String:"C String"]; NSLog(@"objectString = %@", objectString); In order to find a string inside another string, you can use the rangeOfString: method of NSString. The return value of this method is of type NSRange: typedef struct _NSRange { NSUInteger location; NSUInteger length; } NSRange; If the string that you are looking for (needle) is found inside the target string (haystack), the location member of the NSRange structure will be set to the zero-based index of the first character of needle in haystack. If needle cannot be found in haystack, the loca tion member gets set to NSNotFound. Let's have a look at an example: NSString *haystack = @"My Simple String"; NSString *needle = @"Simple"; NSRange range = [haystack rangeOfString:needle]; if (range.location == NSNotFound){ /* Could NOT find needle in haystack */ } else { /* Found the needle in the haystack */ NSLog(@"Found %@ in %@ at location %lu", needle, haystack, (unsigned long)range.location); } The search done by the rangeOfString: method of NSString class is case- sensitive. If you want to have more control over how your search is done on a string, you can use the rangeOfString:options: method, where the optionsparameter is of type NSString CompareOptions. enum { NSCaseInsensitiveSearch = 1, NSLiteralSearch = 2, NSBackwardsSearch = 4, NSAnchoredSearch = 8, NSNumericSearch = 64, NSDiacriticInsensitiveSearch = 128, NSWidthInsensitiveSearch = 256, NSForcedOrderingSearch = 512, NSRegularExpressionSearch = 1024 }; typedef NSUInteger NSStringCompareOptions; 1.21 Allocating and Making Use of Strings | 77 As you can see, the values in this enumeration are multiples of 2. That indicates that you can mix them with the logical OR operator (the | pipe character). Let's say we want to search for a string inside another string but we are not concerned about the case- sensitivity of the search. All we want is to find a string inside another string, whether the case matches or not.Here is how we can do it: NSString *haystack = @"My Simple String"; NSString *needle = @"simple"; NSRange range = [haystack rangeOfString:needle options:NSCaseInsensitiveSearch]; if (range.location == NSNotFound){ /* Could NOT find needle in haystack */ } else { /* Found the needle in the haystack */ NSLog(@"Found %@ in %@ at location %lu", needle, haystack, (unsigned long)range.location); } You can see that we are using the rangeOfString:options: method of NSString with the NSCaseInsensitiveSearch value, which tells the runtime that we want the search to be performed without any regard to case-sensitivity. Mutable strings are similar to immutable strings. However, they can be modified during runtime. Let's see an example: NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@"My MacBook"]; /* Add string to the end of this string */ [mutableString appendString:@" Pro"]; /* Remove the "My " string from the string */ [mutableString replaceOccurrencesOfString:@"My " withString:[NSString string] /* Empty string */ options:NSCaseInsensitiveSearch /* Case-insensitive */ range:NSMakeRange(0, [mutableString length])]; /* All to the end */ NSLog(@"mutableString = %@", mutableString); When the mutableString string gets printed to the console, you will see this: mutableString = MacBook Pro You can see that we started with the string "My MacBook" and then removed the "My " string from that original string. So now we have "MacBook". After this, we appended the string " Pro" to the end of this string to get the final value, which is "MacBook Pro". See Also XXX 78 | Chapter 1: The Basics 1.22 Allocating and Making Use of Numbers Problem You need to use integral values or encapsulate numbers in objects. Solution Use NSNumber for an object-oriented approach to handling numbers. If you require sim- ple numbers (non-objects), use NSInteger to hold signed (positive and negative) values, NSUInteger to hold unsigned (only positive or zero) values, and CGFloat and double to hold floating point values. Discussion Just as we place strings inside instances of NSString, we can place numbers inside in- stances of NSNumber. Why, you might ask? The answer is simple: to have allow an object to carry the value of our numbers so that we can save this value to disk easily, load it from disk, and simply allow a single object to carry signed and unsigned integral and floating point values, without the need for typecasting or defining multiple variables. The possibilities are virtually endless. Let's have a look at constructing instances of NSNumber: NSNumber *signedNumber = [NSNumber numberWithInteger:-123456]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456]; NSNumber *floatNumber = [NSNumber numberWithFloat:123456.123456f]; NSNumber *doubleNumber = [NSNumber numberWithDouble:123456.1234567890]; Just as we placed signed and unsigned integers and floating point values into an instance of NSNumber class, we can retrieve those values back using some really handy instance methods of NSNumber class, as shown here: NSNumber *signedNumber = [NSNumber numberWithInteger:-123456]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456]; NSNumber *floatNumber = [NSNumber numberWithFloat:123.123456f]; NSNumber *doubleNumber = [NSNumber numberWithDouble:123.1234567890]; NSInteger signedValue = [signedNumber integerValue]; NSUInteger unsignedValue = [unsignedNumber unsignedIntegerValue]; CGFloat floatValue = [floatNumber floatValue]; double doubleValue = [doubleNumber doubleValue]; NSLog(@"signedValue = %ld, \n"\ "unsignedValue = %lu \n"\ "floatValue = %f \n"\ "doubleValue = %f", (long)signedValue, (unsigned long)unsignedValue, floatValue, doubleValue); 1.22 Allocating and Making Use of Numbers | 79 Here are the methods of NSNumber that we used in this code to actually generate instances of NSNumber class: numberWithInteger: Encapsulates an integer into an instance of NSNumber. numberWithUnsignedInteger: Encapsulates an unsigned integer (only positive or zero numbers) into an instance of NSNumber. numberWithFloat: Encapsulates a floating point value into an instance of NSNumber. numberWithDouble: Encapsulates a double value into an instance of NSNumber. And here are the methods which we used to extract pure numbers from instances of NSNumber: integerValue Returns an integer of type NSInteger from the NSNumber on which this method is called. unsignedIntegerValue Returns an unsigned integer of type NSUInteger from the NSNumber on which this method is called. floatValue Returns a floating point value of type CGFloat from the NSNumber on which this method is called. doubleValue Returns a double value of type double from the NSNumber on which this method is called. If you want to compare a number to a string, simply convert it to any of the raw integral/ float values that you think can contain the whole of that number, and then format your string using a format identifier that suits your data. For instance, to turn an unsigned integer into an instance of NSString, you can use the %lu format specifier, like so: NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456]; /* Convert an unsigned integer inside an NSNumber to NSString */ NSString *numberInString = [NSString stringWithFormat:@"%lu", (unsigned long)[unsignedNumber unsignedIntegerValue]]; NSLog(@"numberInString = %@", numberInString); Keep in mind that any class method of NSNumber class that starts with numberWith returns an autorelease instance of that NSNumber. To remove the burden on your autor- elease pools, you can use the initWith methods of the NSNumber class after allocating your number, like so: 80 | Chapter 1: The Basics NSNumber *unsignedNumber = [[NSNumber alloc] initWithUnsignedInteger:123456]; See Also XXX 1.23 Allocating and Making Use of Arrays Problem You want to store a series of objects into another object for later use. Solution Use NSArray and NSMutableArray classes to store objects into arrays that are fixed and that you can change, respectively. Discussion An object of type NSArray or any of its subclasses has the capability to store n number of other objects. These objects can then be accessed using their index. For instance, let's say you have 10 pair of socks. Now imagine placing them all on a flat surface from left to right, you call them, socks 1, socks 2, socks 3, etc. So the leftmost sock is now addressed as socks 1, the one next to it is called socks 2, etc. Isn't that easier than saying something like "the blue socks next to my red socks"? That's exactly what arrays do: they make arranging items much easier. You can place any object of type NSObject or any of its subclasses into an array of type (or subclasses of) NSArray The primary difference between NSArray and NSMutableArray is that a mutable array can be changed/modified after it has been allocated and intialized, whereas an immut- able array, NSArray, cannot. Let's have a look at an example. Let's create an instance of NSString and two instances of NSNumber and place them in an immutable array: NSString *stringObject = @"My String"; NSNumber *signedNumber = [NSNumber numberWithInteger:-123]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123]; NSArray *array = [[NSArray alloc] initWithObjects: stringObject, signedNumber, unsignedNumber, nil]; 1.23 Allocating and Making Use of Arrays | 81 NSLog(@"array = %@", array); When you run this program, you get the following text printed to your console: array = ( "My String", "-123", 123 ) As you can see, we used the initWithObjects: initializer of the array. When using this initializer, pass your objects that need to be placed inside the array, one by one. At the end, terminate the list with a nil so that the runtime knows when you are terminating your list. If you don't do so, the LLVM Compiler will throw a warning similar to this: warning: Semantic Issue: Missing sentinel in method dispatch We can also use the arrayWithObjects: class method of NSArray to create an autorelease array, like so: NSArray *array = [NSArray arrayWithObjects: stringObject, signedNumber, unsignedNumber, nil]; You can call the count method on your array to get the number of objects in that array. You can go through your array using a for loop or using an enumerator. Let's have a look at the solution with a for loop first: NSArray *array = [NSArray arrayWithObjects: stringObject, signedNumber, unsignedNumber,nil]; NSUInteger counter = 0; for (counter = 0; counter < [array count]; counter++){ id object = [array objectAtIndex:counter]; NSLog(@"Object = %@", object); } And here is the output: Object = My String Object = -123 Object = 123 As you can see, we use the objectAtIndex: method to get an object at a specific index. Remember that indexes are zero-based. In other words, when the counter reaches -1, the loop has to stop because there can be no negative indexes in an array. 82 | Chapter 1: The Basics [...]... @"String 2" , @"String 4", @"String 1", @"String 3", nil]; [myArray sortUsingComparator: ^NSComparisonResult( strong id obj1, strong id obj2) { NSString *string1 = (NSString *)obj1; NSString *string2 = (NSString *)obj2; return [string1 compare:string2]; }]; NSLog(@"myArray = %@", myArray); The results will then be printed to the console, as follows: myArray = ( "String "String "String "String ) 1", 2" ,... to value 2 (right) is ascending, meaning that value 1 is smaller NSOrderedDescending The value on the right is smaller than the value on the left In other words, the transition from value 1 (left) to value 2 (right) is descending, meaning that value 1 is bigger than value 2 1 .23 Allocating and Making Use of Arrays | 85 So if we get String 3 as value 1 (left) and then get String 1 as value 2 (right),... Also XXX 1. 25 Allocating and Making Use of Sets | 91 1 .26 Creating Bundles Problem You want to group your resources into hierarchical structures and be able to access those resources at run time with ease Solution Follow these steps to successfully create a bundle: 1 Create a root folder on your disk that will later become your bundle For instance, let's give this folder the name Resources 2 Under the... Recipe 1 .26 to create a bundle called Resources.bundle and place it inside your main bundle Discussion If you have followed the instructions in Recipe 1 .26 , you now have a bundle called Resources.bundle inside this bundle you have a folder called Images Let's now put an image inside this folder After I placed an image called AlanSugar.png into the bundle Figure 1- 35 shows what the bundle contains 1 .28 Loading... have a look at an example: NSString *stringObject = @"My String"; NSNumber *signedNumber = [NSNumber numberWithInteger:- 123 ]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger: 123 ]; NSArray *anotherArray = [[NSArray @"String @"String @"String alloc] initWithObjects: 1", 2" , 3", nil]; NSMutableArray *array = [[NSMutableArray alloc] initWithObjects: stringObject, signedNumber, nil]; [array... have a look at its output: Object Object Object Object Object = = = = = My String 123 String 1 String 2 String 3 You might be asking, "what just happened?" Well, let's have a look what methods of the NSMutableArray class we actually used: addObject: This method allows us to add an object to the end of a mutable array 1 .23 Allocating and Making Use of Arrays | 83 removeObject: Using this method, we can... enumerateObjectsUsingBlock: method of NSArray accepts a block object as its parameter For more information about enumerateObject sUsingBlock: and the block object it accepts, please refer to Recipe 1. 25 See Also XXX 1 .29 Sending Notifications with NSNotificationCenter Problem You want to broadcast an event in your app and allow any object that is willing to listen to it to take action, depending on the notification... an array: NSArray *person = [[NSArray alloc] initWithObjects: @"Anthony", @"Robbins", [NSNumber numberWithUnsignedInteger :51 ], nil]; NSLog(@"First Name = %@", [person objectAtIndex:0]); NSLog(@"Last Name = %@", [person objectAtIndex:1]); NSLog(@"Age = %@", [person objectAtIndex :2] ); 86 | Chapter 1: The Basics You can see that we are using an index into the array to access each one of these values With... folders with a bundle extension They have two main distinctions from regular folders: 1 Cocoa Touch provides an interface through which you can access bundles and their resources really easily 92 | Chapter 1: The Basics 2 If a bundle is added to the Navigator on the left hand side of Xcode, any files added to or removed from the bundle outside Xcode will, respectively, appear in or disappear immediately from... nil){ NSLog(@"Successfully loaded the file as an image."); } else { NSLog(@"Failed to load the file as an image."); } } else { NSLog(@"Could not find this file in the main bundle."); 1 .27 Loading Data From the Main Bundle | 95 } self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; . [NSNumber numberWithInteger:- 123 456 ]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger: 123 456 ]; NSNumber *floatNumber = [NSNumber numberWithFloat: 123 456 . 123 456 f]; NSNumber *doubleNumber. [NSNumber numberWithInteger:- 123 456 ]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger: 123 456 ]; NSNumber *floatNumber = [NSNumber numberWithFloat: 123 . 123 456 f]; NSNumber *doubleNumber. around 30% of iOS devices today are running iOS versions that are about a year or a year and a half old. If today we are working with iOS 5, there are still iOS devices out there running iOS, 3 for

Ngày đăng: 13/08/2014, 18:20