I just had a ridonkulous typo in my iPhone app, answered here.
Now I'm wondering about the #"..." notation.
why this works:
NSArray *someArray = [NSArray arrayWithObjects: #"Fairfield", nil];
and this does not (even though it compiles, it will throw an EXC_BAD_ACCESS):
NSArray *someArray = [NSArray arrayWithObjects: "#Fairfield", nil];
Edit:
Ok, so you guys have pointed out that I can't add a C string to an NSArray, because it's obviously not an object.
Now another question: Isn't this somewhat of an oversight? I mean, why does the "...WithObjects:" message specify a list of (id) instead of (NSObject *)?
"#Fairfield" is a normal C string with an '#' character in it. #"Fairfield" is an Objective-C string (NSString on OS X) with no literal '#' in it.
You cannot add C strings to Cocoa collections.
It accepts id rather than NSObject because all initialisers return id. All initialisers return id because subclasses would otherwise override the return type of their ancestors' initialisers.
For example, -[NSMutableString init] can't return NSMutableString * because it subclasses -[NSString init], which can't return NSString * because it overrides -[NSObject init].
Unfortunately, implicit type-casting between const char * and id is perfectly legit, so the compiler won't throw a warning, however a static analyser may be able to pick this sort of mishap up fairly easily.
"Fairfield" is a C string, #"Fairfield" is an Objective-C string.
#"Fairfield" is an object (NSString), so you can send it methods ([#"Fairfield" uppercaseString]) and add it to Objective-C arrays ([NSArray arrayWithObjects:#"Fairfield",nil]). You can only add objects to NSArrays.
On the other hand, "Fairfield" is a C string, and is generally not used in Cocoa. For the most part, you can get by with only using #"Fairfield"
The other reason that a number of things in Cocoa deal with id rather than NSObject* is because, unlike some other languages (say, Java and C#), where all objects in the language must inherit from some global base class, it's entirely possible to have objects that do not descend from NSObject (NSProxy being one example). It's not something you'd do often, but it is possible. The id type means "pointer to any Objective C instance".
Related
I'm a little bit confused about the syntax of NSLog. For example,
NSString *nameString = #"Name";
NSLog(#"nameString is: %#", nameString);
If my understanding is correct (which it very well may not be), then nameString is defined to be a pointer to a String. I thought then that this would print the memory address that nameString holds, not the value of that address. So, if that is true, then in the NSLog statement, to get the value of the pointer, shouldn't we need to use the asterisk notation to access what nameString points to like this:
NSLog(#"nameString is: %#", *nameString);
?
It has been a little while since programming in C, but since Objective-C is a superset of C I thought they would behave similarly.
An explanation would be greatly appreciated! Thanks!
The command %# is like "shortcut" that calls the method -description on the receiver. For an NSString it simply display the string itself, since is inherited from NSObject you can override it, very usefull if you create for own class. In that case the default behaviur is print the value of the pointer. If you want to print the address of the pointer in the string just replace with :
NSLog(#"nameString is: %p", nameString)
I think that you use an asterisk only to declare a pointer. Then, you only use the name you decided. For example:
NSString *foo = [[NSString alloc] initWithString:#"Hello"];
NSLog(#"%#", foo);
Correct me if I am wrong :)
It's an object and NSLog is a function that uses its format specifiers to determine what to do with the argument. In this case the specifier is %# which tells NSLog to call a method on an object.
Normally this will call the method "description" which returns an NSString but it probably does respondsToMethod first and falls through to some other string methods.
What is the difference between mutable and immutable?
Such as:
NSString vs NSMutableString.
NSArray vs NSMutableArray.
NSDictionary vs NSMutableDictionary.
What is the difference between a mutable object and the other object [which I assume is immutable]?
A mutable object can be mutated or changed. An immutable object cannot. For example, while you can add or remove objects from an NSMutableArray, you cannot do either with an NSArray.
Mutable objects can have elements changed, added to, or removed, which cannot be achieved with immutable objects. Immutable objects are stuck with whatever input you gave them in their [[object alloc] initWith...] initializer.
The advantages of your mutable objects is obvious, but they should only be used when necessary (which is a lot less often than you think) as they take up more memory than immutable objects.
The basic difference is:
NSStrings cannot be edited, only reassigned. This means when the value of an NSString changes, it is actually pointing to a new location in memory.
NSMutableString objects can be edited and maintain the same pointer.
A common practical difference is:
If you create 1 NSString and then assign another one to it, then edit either one of them, they will now be pointing to different strings.
If you do the same thing with NSMutableStrings, but then just edit one of them (not reassign it), they will both be pointing to the newly edited object.
Mutable objects can be modified, immutable objects can't.
Eg:
NSMutableArray has addObject: removeObject: methods (and more), but NSArray doesn't.
Modifying strings:
NSString *myString = #"hello";
myString = [myString stringByAppendingString:#" world"];
vs
NSMutableString *myString = #"hello";
[myString appendString:#" world"];
Mutable objects are particularly useful when dealing with arrays,
Eg if you have an NSArray of NSMutableStrings you can do:
[myArray makeObjectsPerformSelector:#selector(appendString:) withObject:#"!!!"];
which will add 3 ! to the end of each string in the array.
But if you have an NSArray of NSStrings (therefore immutable), you can't do this (at least it's a lot harder, and more code, than using NSMutableString)
A mutable object can be mutated or changed. An immutable object cannot. For example, while you can add or remove objects from an NSMutableArray, you cannot do either with an NSArray.
The english definition of "mutable" is really all you need here. Mutable objects can be modified after creation. Immutable objects cannot be modified after creation. That applies to all of the classes you listed.
Practically speaking, all of the mutable classes are subclasses of the immutable ones, and each adds its own interface to allow programmatic modification of the object, like addObject:, setObject:forKey:, etc...
Everyone says you can't change/modify an immutable object. I have a different way of explaining. You can modify it, but then you would be creating a new pointer to the new object, its not like you modified the old object, its a brand. New. Object. Any pointer that had a previously pointing pointer to it, would not see its change. However if its a Mutable Object, any previously pointing object to it would be seeing its new value. See the examples.
FYI %p prints the pointer location in heap.
NSString * A = #"Bob";
NSString * B = #"Bob";
NSString * C = #"Bob1";
NSString * D = A;
NSLog(#"\n %p for A \n %p for B \n %p for C \n %p for D",A,B,C,D);
// memory location of A,B,D are same.
0x104129068 for A
0x104129068 for B
0x104129088 for C
0x104129068 for D
Modifying pointer A's object
A = #"Bob2"; // this would create a new memory location for A, its previous memory location is still retained by B
NSLog(#"\n%p for A \n%p for B \n%p for C \n %p for D",A,B,C, D);
// A has a **new** memory location, B,D have same memory location.
0x1041290c8 for A
0x104129068 for B
0x104129088 for C
0x104129068
for D
// NSMutableString * AA = #"Bob"; <-- you CAN'T do this you will get error: Incompatible pointer types initializing NSMutableString with an Expression of type NSString
NSMutableString * AA = [NSMutableString stringWithString:#"Bob1"];
NSString * BB = #"Bob";
NSString * CC = #"Bob1";
NSString * DD = AA;
NSLog(#"\n %p for AA \n %p for BB \n %p for CC \n %p for DD",AA,BB,CC,DD);
// memory location of AA,DD are same.
0x7ff26af14490 for AA
0x104129068 for BB
0x104129088 for CC
0x7ff26af14490 for DD
Modifying pointer AA's object
AA = (NSMutableString*)#"Bob3"; // This would NOT create a new memory location for A since its Mutable-- D was and still pointing to some location
NSLog(#"\n%p for AA \n%p for BB \n%p for CC \n %p for D",AA,BB,CC,DD);
// memory location of AA,DD are NOT same.
0x104129128 for AA
0x104129068 for BB
0x104129088 for CC
0x7ff26af14490 for DD
As you would imagine, the default storage attribute for all NSString properties is retain. For more information on copy & retain I highly suggest you read this question.NSString property: copy or retain?
Mutable can be changed, immutable cannot.
When you share a mutable objects, you should expected the some one can change it.
When you share an immutable object, you expected the no one will changed.
There are some other difference which are interesting a immutable object when copied will instead be retained. There may also be lots of under the hood differences that apple implements for performance reason depend on whether a object is mutable or not, for example, do the substring methods copy the actual bytes of their parent string or do the just point a subrange of the parent string if it is immutable, probable not but who knows.
Immutability as: “not capable of or susceptible to change” and mutability as “capable of change or of being changed”.
To rephrase immutable means can’t be changed and mutable means can be changed.
In swift code, we apply the concepts of immutability and mutability using the keywords let and var respectively.
for more detail visit this link it has detail description with code
Mutable variables
// Declaration and assignment of a mutable variable name.
var name = "Kory"
// Reassignment or mutation of the variable name.
name = "Ryan"
Above we declared a variable named “name” and assigned its value to be the String literal “Kory”. On line five we reassigned the variable to be the String literal “Ryan”.
This is an example of a mutable variable. Using the keyword var allows us to change the value the variable holds. The variable “name” can be changed to whatever String we like.
Mutable variables are needed when the value of a variable is expected to change. Let’s take a look at a slightly more complicated example.
// Declares a new type Person
struct Person {
var name: String
var age: Int
}
// Creates an instance of person named kory.
var kory = Person(name: "Kory", age: 30)
// Mutates Kory's properties
kory.age = 31
kory.name = "Scooby"
In the above example both the name and age properties of instance of a Person are mutable, they can be changed. In this example mutability is important. A person’s name or age can and will change in real life. Having mutable variables allows our data too closely resemble the real world thing we are trying to model.
Immutable contants
Often the words variable and constants are used interchangeably but there is a subtle difference. Mutability. Variables as the name implies can vary with the data they hold. Constants cannot and are therefore are immutable and in other words constant. Swift allows us to represent an immutable constant with the keyword “let”. Consider the below example.
// Declaration and assignment of a mutable variable name.
let name = "Kory"
name = "Ryan" // Cannot assign to property: 'name' is a 'let' constant
The above example is nearly identical to the mutable example but will not compile. When an identifier such as “name” is set to be immutable with the keyword “let” it cannot be changed once assigned. You can delay assignment as illustrated below. But you cannot change name once it has been assigned.
let name: String
// Some important code here
name = "Kory"
You can also use constants inside of structs and classes when you want to make one or more properties immutable even if the instance is declared as mutable.
// Declares a new type Person with constants properties
struct Person {
age name: String
let age: Int
}
var kory = Person(name: "Kory", age: 30)
kory.name = "Ryan"
kory.age = 30 // Cannot assign to property: 'age' is a 'let' constant
Even though kory is declared with var, internally age is declared with let and cannot be mutated. Mutating name is fine.
The book "iPhone Programming. The Big Nerd Ranch Guide" cites the following method (page 96)
(void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *) views {
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 250, 250);
[mv setRegion:region animated:YES];
}
I'm confused because of the asterisk usage. The line that begins with "MKAnnotationView" and the following one can be represented in an abstract fashion by:
ObjectType variableName = [object message];
Questions:
In the first case an asterisk precedes the variable name, but not in the second. Why?
In the case where the asterisk is used, should not be the pointer the assigned to nil?
Thanks.
I tend to think of it as what variable types require an asterisk, not what variable names require an asterisk. Objective C doesn't allow you to allocate objects on the stack like so:
// Declare an NSObject. Won't work.
NSObject myObject;
Instead, all objects must be dynamically allocated on the heap using pointers like so:
// Declare a pointer to an NSObject. Will work.
NSObject* myObject = [[NSObject alloc] init];
id is a special Objective C keyword that just means "A pointer to some Objective C object". This may or may not inherit from NSObject and is dynamically typed. What's important to note is that, while there is no asterisk, this is still a pointer to an object:
// Same as before. Will work.
id myObject = [[NSObject alloc] init];
The only difference is that the compiler has no information about what myObject is.
As a finishing note, id <MKAnnotation> is exactly the same as a regular id, but with some extra information for the compiler. Read it as "a pointer to some Objective C object that behaves like an MKAnnotation". MKAnnotation, in this case, is the name of a Protocol whose required methods you are declaring that particular id to implement.
id is already defined as a pointer to a struct. If you look at its definition in objc.h, you would that id is defined as,
typedef struct objc_object {
Class isa;
} *id;
Since it is already a pointer to an objc_object, you can create pointers to objects without using the asterisk as,
id myObject;
Also saying that an object is type id gives the compiler absolutely no information about the object except its class which comes from the isa property.
An NSObject on the other hand is defined as,
#interface NSObject <NSObject> {
Class isa;
}
To create a pointer to an object of NSObject or one of its subclass (such as MKAnnotationView), you would declare it as,
NSObject *myObject;
MKAnnotationView *myObject;
We are putting the asterisk here to denote that it is a pointer.
Specifying the protocol(s) next to the type gives the compiler more information for static-type checking.
You should check out this article for a brief introduction to the differences between id and NSObject. For an in-depth understanding, checkout this article on the Objective-C runtime.
ObjectType is normally something like "pointer to a MKAnnotationView", which is represented in Objective-C as it is in C: "MKAnnotationView *". Exceptions include the "id" type, various integer and floating point types (including their typedefs), enums (which are really integer types), and some small structs like CGRect.
What kind of information is stored behind such an enum type thing? Example:
typedef enum {
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear
} UIViewAnimationCurve;
I am not sure if I can safely add such an enum constant to an array. Any idea?
Enums in Objective-C are exactly the same as those in C. Each item in your enum is automatically given an integer value, by default starting with zero.
For the example you provided: UIViewAnimationCurveEaseInOut would be 0; UIViewAnimationCurveEaseIn would be 1, and so on.
You can specify the value for the enum if required:
typedef enum {
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn = 0,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear
} UIViewAnimationCurve;
This result of this would be: UIViewAnimationCurveEaseInOut is 0; UIViewAnimationCurveEaseIn is 0; UIViewAnimationCurveEaseOut is 1; and so on. However, for basic purposes you shouldn't need to do anything like that; it just gives you some useful info to toy with.
It should be noted based on the above, that an enum can't assume to be a unique value; different enum identifiers can be equal in value to each other.
Adding an enum item to a NSArray is as simple as adding an integer. The only difference would be that you use the enum identifer instead.
[myArray addObject:[NSNumber numberWithInt:UIViewAnimationCurveEaseInOut]];
You can check this out for yourself by simply outputting each enum to the console and checking the value it provides you with. This gives you the opportunity to investigate the details of how it operates. But for the most part you won't really need to know on a day to day basis.
Enums are typically int values. You can store them in an array by wrapping them in an NSNumber:
[myMutableArray addObject:[NSNumber numberWithInt:myAnimationCurve]];
... then get them back out like this:
UIViewAnimationCurve myAnimationCurve = [[myMutableArray lastObject] intValue];
Enums in Objective-C are the same as enums in vanilla C. It's just an int. If you're using an NSArray, then it expects a pointer and you'll get a warning if you try to add an int to it:
NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:UIViewAnimationCurveEaseInOut];
// Last line results in:
// warning: passing argument 1 of 'addObject:' makes
// pointer from integer without a cast
If you're storing a large collection of 32-bit integers, consider using the appropriate CF collection type rather than the NS collection type. These allow you to pass in custom retain methods, which gets rid of the need to box every integer added to the collection.
For example, let's say you want a straight array of 32-bit ints. Use:
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
The last parameter tells the array to not retain/release the "addresses" you pass in to it. So when you do something like this:
CFArrayAppendValue(arrayRef, 1);
What the array thinks is that you're passing in a pointer to an object living at the memory address 0x1. But since you told it to not call retain/release on that pointer, it gets treated as a standard int by the collection.
FWIW, for educational value, standard NSMutableArrays have equivalent CF types. Through toll-free bridging you can use the CF collection as a standard Foundation collection:
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, kCFTypeArrayCallbacks);
NSMutableArray *array = (NSMutableArray *)arrayRef;
[array addObject:#"hi there!"];
NSLog(#"%#", [array objectAtIndex:0]); // prints "hi there!"
You can apply the same tricks to dictionaries (with CFDictionary/CFMutableDictionary), sets (CFSet/CFMutableSet), etc.
Are there any gotchas for Toll free bridging between NS and CF types?
I'm not sure if I'm doing it wrong but I can't seem to use CF opaque types like ABAddressID inside of an NS Array.
There are not too many 'gotchas'. But this is a C based language, so not every item descends from a CFType. For instance an ABRecordID is really just a 32 bit integer. So its not a CFType. To add ABRecordIDs to an array you would do something like this:
NSMutableArray* newArray = [NSMutableArray array];
ABRecordID someID = 24875247; // you get this somewhere from some call
[newArray addObject:[NSNumber numberWithInt:someID]]; // adds an ABRecordID to the array by putting the int into an NSNumber
Then later when you want the number back:
ABRecordID thatID = [[newArray objectAtIndex:0] intValue]; // retrieve the number, then ask for its int value.
If you read the documentation on a CFType, it will always say whether it is toll free bridged with some NS* counterpart.
Quote from the docs:
"CFNumber is “toll-free bridged” with its Cocoa Foundation counterpart, NSNumber. This means that the Core Foundation type is interchangeable in function or method calls with the bridged Foundation object. Therefore, in a method where you see an NSNumber * parameter, you can pass in a CFNumberRef, and in a function where you see a CFNumberRef parameter, you can pass in an NSNumber instance. This fact also applies to concrete subclasses of NSNumber. See Integrating Carbon and Cocoa in Your Application for more information on toll-free bridging."
But an int in C is most definitely NOT a CFNumber.
Hope that helps,
--Tom