This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am new to Objective-C so please do forgive me if this question is silly! But I would like to know what that means.
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
What these lines do in a detail view controller exactly? Does it mean that a new object, i.e newDetailItem is created and assigned to the already existing detailItem? I don't get the idea of it.
OR
Does it actually mean that this new object is is equal to the details that are present in the "detailItem" already. So, shouldn't it be written as newDetailItem = _detailItem, so that this new object will get the values of _detailItem?
This has kind of confused me a bit :(
Thanks for your time!
The code you are showing is a typical example of a "setter"—a method that assigns a new value to a property; in this case, a property called "detailItem".
This method is generally invoked in one of two ways, either explicitly:
[someObject setDetailItem:someDetailItem];
or via dot notation:
someObject.detailItem = someDetailItem;
_detailItem is an instance variable, or "ivar"; it is an object-local place where the value of the property is actually stored. This code checks to make sure the new value assigned is actually different from the old value, then assigns it and invokes a side effect, presumably updating some UI to display the new value.
Your confusion seems to stem, in part, from the name of the parameter to this method, "newDetailItem". The name here is arbitrary, and doesn't imply that anything is being created. It's new in the sense of being a new value for the property to have, not a new object.
This method is setting the new value newDetailItem to _detailItem.
In this statment if (_detailItem != newDetailItem) it is checking if both are same object or not, by comparing there memory locations.
In _detailItem = newDetailItem; newDetailItem that is passed as id is put to _detailItem.
In case of ARC: The value is retained/copy as in ARC this is not specified.
You are accessing your property directly by _detailItem. You have a property called detailItem in your class.
And then calling a method configureView.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to reset the state of this statement:
[[IAPManager sharedInstance]isProductPurchased:kInAppItem] = FALSE;
However, i'm getting the error of "Assigning to 'readonly' return result of an Objective-C message not allowed". How do i reset the state of this statement?
In IAPManager.m
-(BOOL)isProductPurchased:(NSString *)productIdentifier
{
return [_purchasedProducts containsObject:productIdentifier];
}
Your left hand side is a method invocation that returns a BOOL, it is not a reference to the property itself, so you cannot assign a value.
You need to refer to the code for IAPPurchase, but if it this library then there is no method to reset the purchased state for a product.
You can delete the app or delete the plist the library uses to store purchase data (by the way, this isn't a very secure way of recording in-app purchases)
You can't assign a value to a return value of a method in Objective-C. You may be confused by the syntax
myObject.myProperty = myValue;
This sets the value of myProperty to myValue, but in doing so it essentially calls this method:
[myObject setMyProperty:myValue];
Either way, the left side of your code will be handled as a return value, not a property. Therefore you can't assign it.
If there exists a method like setProductPurchased: or setIsProductPurchased:, you need to call that like the second example. Otherwise there isn't a way to set the property, so you may have to set an instance variable directly.
I have a form that I'm creating and to simplify things, I'm trying to create a form field mapper to an object. As such, I create the following dictionary:
self.fieldPropertyMapper = #{
#(CompanyFieldName):self.company,
#(CompanyFieldDescription):self.company.description,
#(CompanyFieldWebsite):self.company.website,
#(CompanyFieldTwitter):self.company.twitter,
#(CompanyFieldAddress):self.company.address,
#(CompanyFieldAddress2):self.company.address2,
#(CompanyFieldCity):self.company.city,
#(CompanyFieldState):self.company.state,
#(CompanyFieldZipcode):self.company.zipcode,
#(CompanyFieldPhone):self.company.phone
};
The keys here are members of the CompanyFieldType enum.
My goal here is to later in my form to assign a value to the returned pointer. Here's what I mean: when a text field in one of my forms stops editing, I'm looking to set the value. Here's what I'd like to accomplish:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CompanyFieldType fieldType = [self fieldTypeForTag:textField.tag];
// Set the value of the respective company property
// In theory it would be something like:
// self.fieldPropertyMapper[#(fieldType)] = textField.text;
}
I'm assuming there's a way to assign by reference but I'm forgetting how to do this. (Is it using the & symbol or **?) I don't remember. Help appreciated! If I'm messing up my terminology, feel free to let me know.
You can't do exactly what you want to do. That is to say, there is no pointer magic that will do what you want.
You can get essentially the same effect, though, with key-value coding. Instead of storing the result of accessing the property (e.g. self.company.website), instead you want to just store the key path to the value you're interested in as a string — e.g. #"company.website". Then you can do like so:
[self setValue:textField.text forKey:self.fieldPropertyMapper[textField.tag]];
Using NSMapTable initialized with NSPointerFunctionsStrongMemory for the keys and NSPointerFunctionsOpaqueMemory for the values. Then you could store the addresses of your iVars backing your properties as the values in the table.
[self.mapTable setObject:&_company forKey:#(CompanyFieldName)];
Haven't tested this but this should get you started.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
In a for loop,
NSLog (#"%#", [[<array> objectAtIndex:i]-><specific_var>];
Each index position should have two vars and I'd like to access one of them. Thanks much.
Edited: in this case I'm trying to access a property
You're far better off creating a temporary local variable. It will help you get access to the property without using -> and make your code clearer.
E.g.
TheObject *object = array[i]; //same as [array objectAtIndex:i]
NSLog(#"%#", object.property);
The only time we apply -> to an Objective-C object (other than self) is when we want to access the object's instance variables from outside of a method on that object. And we almost never want to do that.
Anyway, the return type of the objectAtIndex: method is id. An id has no public instance variables.
If you know the objects in your array are of a specific type, and you want to access the instance variables of those objects directly (which is generally strongly frowned upon), you must cast the return value to the correct type first. Example:
NSLog(#"%#", ((MyObject *)[myArray objectAtIndex:i])->_myInstanceVariable);
But generally you are much better off using accessor methods, which usually don't require you to cast from id to a more specific type.
More easily using the literal syntax:
NSLog(#"%#", [someArray[i] someGetter]);
or is it is an array of arrays:
NSLog(#"%#", someArray[i][someIndex]);
I suspect the solution to what I'm trying to do is fairly straight forward--yet, I'm unable to get it working myself.
Here's what I'm trying to do: I've built a card game that is initialized with the cards when the game loads. Now, some of those cards have certain properties (card type, card name, as well as a special array). The card type and card name objects are fairly easy to retrieve since they're just one object (and I can call using objectatindex). However, the special array contains several keywords that fluctuate depending on which card is chosen. So instead of initializing these keywords one by one (like I did for card type and card name), I put them into their own special array.. or an array within an array. Here's my code:
itemObjects class:
#synthesize cardName=_cardName;
#synthesize cardType=_cardType;
-(id) initWithCardName:(NSString*)cardName initWithCardType:(NSString*)cardType initWithSpecialArray:(NSArray*) specialArray{
self=[super init];
if (self){
_cardName=cardName;
_cardType=cardType;
}
return self;
}
model class
-(NSMutableArray*)deck{
if (_deck==nil){
_deck=[[NSMutableArray alloc]initWithObjects:
[[itemObjects alloc]initWithCardName:#"The Long Way" initWithCardType:#"bill" initWithSpecialArray:[[NSArray alloc]initWithObjects:#"fast", #"high", nil]],
[[itemObjects alloc]initWithCardName:#"A Short Cut" initWithCardType:#"bill" initWithTrendArray:[[NSArray alloc]initWithObjects:#"small", #"tall", nil]],nil];
View Controller class (this is where I'm trying to call one of the objects, "fast" for example, but with no success
NSString* testing=[[[self.model.deck objectAtIndex:indexPath.row]arrayForKey:#"specialArray"]objectAtIndex:0];
NSLog(#"%#",testing);
I believe I've initialized my "specialArray" correctly and the issue is with how I'm attempting to call it but if I've made a mistake there, any advice would be much appreciated. Thanks!
EDIT: This particular issue has been solved thanks to WendiKidd. It turned out that I wasn't initializing my specialArray correctly. This has led to a separate issue which I have linked to here. I've also posted my corrected code below for those interested in the future:
#synthesize cardName=_cardName;
#synthesize cardType=_cardType;
#synthesize specialArray=_specialArray;
-(id) initWithCardName:(NSString*)cardName initWithCardType:(NSString*)cardType initWithSpecialArray:(NSArray*) specialArray{
self=[super init];
if (self){
_cardName=cardName;
_cardType=cardType;
_specialArray=specialArray;
}
return self;
}
You aren't initializing your special array at all. You pass it to initWithCardName, but you're never setting it to anything. You need to store the special array inside that class, just like you do with cardName and cardType.
Secondly, I can't make heads or tails of the line where you're trying to access the special array. You haven't given us the proper information to see where the object is being stored to tell if you're even properly accessing a card object, but I definitely don't see where you've ever used the key #"specialArray" before, so there's no reason to expect that will return anything. However the rest of your data structure works, at some point you're going to have an object of whatever class the initWithCardName function initializes (for example purposes I'm going to go ahead and call it CardObject). To get the info from the special array, you're going to have to save an object called specialArray into the CardObject class, as already mentioned. Then you can write something like this:
CardObject* card = //[whatever you have to do to access the right card object]
for(NSString* specialAttribute in card.specialArray)
{
NSLog(#"Special Attribute: %#", specialAttribute);
}
And that should print all the special attributes of the card quite nicely.
If you really do just want the first item in the list, as your example was trying to access, this should work just fine:
CardObject* card = //[whatever you have to do to access the right card object]
NSLog(#"Special Attribute: %#", [card.specialArray objectAtIndex:0]);
I have an NSMutableArray called selectedUsers to which I am adding objects using a method called addUser. The objects being added are most often of type PLManagedUser (a core data managed object) although sometimes the object could be a string. In any case, if the array already contains the object, I do not want to add it to the array. Here is the code:
- (void)addUser:(id)user withTitle:(NSString *)title {
if (![_selectedUsers containsObject:user]) {
[_selectedUsers addObject:user];
}
}
I have noticed that if I try to add the same user back to back using the above method, the containsObject catches it, and duplicates are not added. However, if I add the same user (with the same memory address) after having added other objects in between, the duplicate will be added.
I am printing the contents of the array each time I add something to confirm that the duplicate objects are in the array.
My question is, is there any obvious reason why containsObject isn't consistently working here?
You need to provide the ability for an object to identify itself as equal to another object of the same class, and to do this you implement the isEqual: and hash methods.
Having said that, the explanation in your question is the opposite of what I would have expected.