Can any one just tell me what the below code in iOS mean? Its a piece of code from MBCalendarKit.
#property (nonatomic, strong) NSMutableDictionary *data;
- (NSArray *)calendarView:(CKCalendarView *)calendarView eventsForDate:(NSDate *)date
{
return [self data][date];
}
How does the above function return an NSArray when the global data is an NSMutableDictionary and the local date is NSDate?
And what does [self data][date] mean?
If data is an NSDictionary then it means exactly the same thing as [data objectForKey:date]. That syntax was introduced a couple of years ago — ideally read the whole thing but if in a hurry then jump to 'Object Subscripting'.
Related
With the new xcode7 Apple introduced generics and nullability to Objective-C ( Developer guide )
But it seems to be very different from what we have on swift.
Nullability:
- (nonnull NSString *)something {
return nil;
}
This should raise a warning! And you can even assign the return value of this method to a nonnull variable like:
//#property (copy, nonnull) NSString *name
obj.name = [obj something];
Generics:
Looking this example:
#property (nonatomic, strong, nonnull) NSMutableArray <UIView *> *someViews;
a warning is raised when something different from a UIView is inserted on the array
[self.someViews addObject:#"foobar"]; //<- this raises an error
but not in this case:
self.someViews = [#[#"foobar"] mutableCopy];
nor in this case:
NSString *str = [self.someViews firstObject];
So the question is, I'm using generics and nullability in a wrong way or they are far away from the Swift implementation?
self.someViews = [#[#"foobar"] mutableCopy];
mutableCopy is inherited from NSObject, where it is declared to return id. It is not declared by NSArray specifically and NSArray des not decide the return type.
NSString *str = [self.someViews firstObject];
This does give a warning for me.
This question already has answers here:
Having trouble adding objects to NSMutableArray in Objective C
(2 answers)
Closed 8 years ago.
For some reason I can't get an array added to a nsmutabledictionary. I have it declared as a property in my .h file here:
#interface TCMExhibitFeedStore : NSObject
#property (nonatomic, strong) NSMutableDictionary *allLevels;
#property (nonatomic, strong) NSMutableDictionary *storedLevels;
+ (TCMExhibitFeedStore *)sharedStore;
- (void)fetchExhibtFeedWithCompletion:(void (^)(NSMutableDictionary *obj, NSError *err))block;
- (TCMLevel *)createLevel:(TCMLevelRemote *)l;
- (TCMExhibit *)createExhibit:(TCMExhibitRemote *)e;
- (BOOL)saveChanges;
#end
Then, I'm trying to add an empty array to it in a function in the .m file like this
[_storedLevels setObject:[[NSMutableArray alloc] init] forKey:#"levels"];
However, when I step through the application this never gets added. Looking in the debugger shows it as
_storedLevels NSMutableDictionary * 0x00000000
NSMutableDictionaries are nothing new to me. I'm just going a bit crazy trying to find my error because this all looks normal to me.
The following lines confuses me...
[_storedLevels setObject:[[NSMutableArray alloc] init] forKey:#"levels"];
Instead of above Use:
self.storedLevels = [[NSMutableDictionary alloc] init];
[self.storedLevels setObject:... forKey:#"levels"];
NOTE: Whenever you see 0x00000000
This means your object is not alloc-ated.
Therefore you need to alloc+init them, before setting any array/value to them.
0x00000000 means nil. All properties and instance variables of Objective C objects are initialized to nil. Hence, we can tell that you have never initialized your properties.
You can to initialize the dictionaries in the designated initializer for TCMExhibitFeedStore. (Or before you access them to add elements)
self.storedLevels = [NSMutableDictionary dictionary];
self.allLevels = [NSMutableDictionary dictionary];
please help me to solve a simple problem.
I am a beginner in objective-c, and I am just switched to objective-c from java. I know java fair well, but not quite super deep into it.
I am building a iphone app. My app is quite simple.
The purpose of my iphone app is to take order with my iphone app in a restaurant.
Progress of My App:
My app only has couple viewPanels and buttons now :)
Here is my app sourcecode, firstview screenshot & secondview screenshot
Problem:
When i click on the Coffee button, my textField wont show up the coffee name & coffee price, which suppose to show up " coffee 1" .
and xcode will take me to the debugger from the iphone similator.(i think its crush at a line so the dubugger took me to the IBaction method and break at the line #synthesize name; It compiles with no error. please help trouble shoot why xcode take me to debugger when i press the coffee button.
SCREEN SHOWS UP RIGHT AFTER PRESS THE COFFEE BUTTON
here is the action code of the coffee button
- (IBAction)Coffee:(id)sender {
int price = 1;
NSString *name = #"coffee";
Storage *order = [[Storage alloc] init];
[order setName:name]; // i assume the program crush at here when it look into setName method.
[order setPrice:price];
[orders addOrders:order];
// Sanity check: // the program not even hit this line yet before crush;
NSLog(#"There are now %d orders in the array.", [orders.getOrders count]);
for (Storage *obj in orders.getOrders){
[check setText:[NSString stringWithFormat:#"%#",[obj description]]]; // check is the TextField instant varible. and the description method is from storage.m to print out the name and price.
}
}
The codes below are my storage classes that store all items that my customer orders.
it is a 2 dimensional array, and My Storages class is a wrapper class of Storage class.
the array format looks like this:
arrayindex1-> name, price
arrayindex2-> name, price
arrayindex3-> name, price
arrayindex4-> name, price
Storage.h
#import <Foundation/Foundation.h>
#interface Storage : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, assign) NSInteger price;
#end
Storage.m
#import "Storage.h"
#implementation Storage
#synthesize name; // program crush and goes to here.
#synthesize price;
- (NSString *)description {
// example: "coffee 1"
return [NSString stringWithFormat:#"%# %d", self.name, self.price];
}
#end
Storages.h
#import <Foundation/Foundation.h>
#import "Storage.h"
#interface Storages : NSObject
#property (nonatomic,strong, readwrite) NSMutableArray *orders;
-(void) addOrders:(Storage *)anOrder;
-(NSMutableArray *) getOrders;
#end
Storages.m
#import "Storages.h"
#implementation Storages
#synthesize orders;
- (id)init {
self = [super init];
if (self) {
orders = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addOrders:(Storage *)anOrder{
[orders addObject: anOrder];
}
-(NSMutableArray *) getOrders{
return orders;
}
#end
There are a couple of problems here.
1) Don't use a pointer for the price property. Generally, unless you're doing something unusual, your properties that are objects will be pointers and your properties that are primitives (NSInteger, BOOL, float, etc) will not be pointers.
2) You will want to make sure that the orders NSMutableArray is initialized with the Storages object, otherwise orders will remain nil and whenever you try to add objects to it, nothing will happen. To initialize the NSMutableArray, do this in your init method as shown below. You can also check that the object is actually getting into a valid mutable array this by putting a simple NSLog statement in the for (Storage *obj in orders.getOrders) { ... } loop and making sure you get at least one iteration through the loop. If orders.getOrders is nil, the work block of the for loop will never get run.
3) It sounds like you need to override (and may have already overridden) the -[NSObject description]method for your Storage object. My guess is you have a mismatch in this method with the -[NSString stringWithFormat:...] format string. For example, you might be using %d or %# in the format string for the NSInteger *. Something like that could definitely cause a crash (which is what I think you mean by "Xcode taking you to the debugger"). For NSIntegers you need to use %d or %i. And as myself and others have mentioned, you want NSInteger here and not NSInteger * and you should change your property declaration.
4) Based on what you have here, I don't think you need the order property in the Storages class at all.
5) Make sure you haven't overlooked the possibility of forgetting to hook up the IBOutlet in Interface Builder to the check textField. A good test for this, besides just confirming it's connected in Interface Builder, would be a reality check test like [check setText:#"This is a test."];
6) Keep in mind that once this works, your for loop is going to execute very quickly, and you'll immediately see only the description for the last object in the orders array. But that doesn't seem to be what your question is about.
I'd suggest you make the following changes:
Storage.h
#import <Foundation/Foundation.h>
#interface Storage : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, assign) NSInteger price;
#end
Storage.m
#import "Storage.h"
#implementation Storage
#synthesize name;
#synthesize price;
- (NSString *)description {
// example: "coffee 1"
return [NSString stringWithFormat:#"%# %d", self.name, self.price];
}
#end
Your IBAction method
- (IBAction)Coffee:(id)sender {
int price = 1;
NSString *name = #"coffee";
Storage *order = [[Storage alloc] init];
[order setName:name];
[order setPrice:price];
[orders addOrders:order];
// Sanity check:
NSLog(#"There are now %d orders in the array.", [orders.getOrders count]);
for (Storage *obj in orders.getOrders){
[check setText:[NSString stringWithFormat:#"%#",[obj description]]]; // check is the TextField instant varible. and the description method is from storage.m to print out the name and price.
}
}
Storages.h
#import <Foundation/Foundation.h>
#import "Storage.h"
#interface Storages : NSObject
#property (nonatomic,strong, readwrite) NSMutableArray *orders;
-(void) addOrders:(Storage *)anOrder;
-(NSMutableArray *) getOrders;
#end
Storages.m
#import "Storages.h"
#implementation Storages
#synthesize orders;
- (id)init {
self = [super init];
if (self) {
orders = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addOrders:(Storage *)anOrder{
[orders addObject: anOrder];
}
-(NSMutableArray *) getOrders{
return orders;
}
#end
What does description do in the following? (I cannot see any description object in Storage class):
[check setText:[NSString stringWithFormat:#"%#",[obj description]]];
I think if you want to print the name the do like:
[check setText:[NSString stringWithFormat:#"%#: %#",obj.name, obj.price]];
You have taken NSInteger pointer in Storages class which is not correct. NSInteger is basic data type and not a pointer. Remove that pointer and use NSInteger variable.
I hope this would resolve your problem.
You could use below code:
#interface Storage : NSObject
#property (nonatomic, retain)NSString *name;
#property (nonatomic, assign)NSInteger price;
You have two mistakes:
1- You declared price as an NSInteger and passed it as a reference. The correct is to pass it as an integer as it is and deal with it as an integer through the whole application.
2- You didn't initialize orders array in Storages class so it will be always nil and will not hold any added object.
You code may looks like:
In the button's IBAction pass the price directly
[order setPrice:price];
In the Storage class
- (NSString *)description {
return [NSString stringWithFormat: #"%# %d", name, price];
}
Add the following to the Storages class
-(id)init
{
if (self = [super init])
{
orders = [[NSMutableArray alloc] init];
}
return self;
}
I have looked at numerous posts which state various ways in which to remove an object from an array correctly, but I am not sure which method is best to use in my instance. I am loading a dictionary from a plist, this dictionary contains numerous arrays, and these arrays contain another dictionary. So I have 3 storage devices setup, 1 to hold the overall dictionary, another for an array, and finally a dictionary to hold the object from the array:
Header:
NSMutableDictionary *questionsDictionary;
NSMutableArray *questionsArray;
NSDictionary *currentQuestion;
#property (nonatomic, retain) NSMutableDictionary *questionsDictionary;
#property (nonatomic, retain) NSMutableArray *questionsArray;
#property (nonatomic, retain) NSDictionary *currentQuestion;
So my first question is to do with the above, are (nonatomic, retain) the right things to use for the following code.
Next I load in my dictionary from the plist:
.m:
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"MultipleChoice.plist"];
self.questionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];
I then setup my question array based upon type based upon my question type:
- (void)setupQuestionType : (NSString *)qType
{
if ([self.questionsDictionary objectForKey:qType])
{
self.questionsArray = [self.questionsDictionary objectForKey:qType];
[self pickRandomQuestion];
}
}
Finally (this is where I get the error), I want to grab the a question at random from this question category:
// Pick a random question number based upon amount of questions
int randomQuestionNum = [[NSNumber numberWithInt:(arc4random() % [self.questionsArray count])] intValue];
// Grab the dictionary entry for that question
currentQuestion = [self.questionsArray objectAtIndex:randomQuestionNum];
// Remove the question from the available questions
[self.questionsArray removeObjectAtIndex:randomQuestionNum]; (Error here)
// Set the question text
self.question.text = [currentQuestion objectForKey:kQuestionkey];
Now if I comment out the removeObjectAtIndex line then the code runs fine, and my question is displayed on the screen. This leads me to believe that it isn't a null pointer. So the logical answer points to the fact that self.questionsArray isn't a NSMutableArray. So I tried the following when setting the array:
- (void)setupQuestionType : (NSString *)qType
{
if ([self.questionsDictionary objectForKey:qType])
{
NSMutableArray *temp = (NSMutableArray *)[self.questionsDictionary objectForKey:qType];
self.questionsArray = (NSMutableArray *)temp;
[self pickRandomQuestion];
}
}
Purely to see if I could type_cast it but the error still occurs. Can anyone shed some light on what I'm doing wrong, or the best approach to take?
Don't typecast NSArray to NSMutableArray. Instead:
NSArray *temp = [self.questionsDictionary objectForKey:qType];
self.questionsArray = [NSMutableArray arrayWithArray:temp];
// code not tested.
I can pass basic data between classes, but when I try to pass a NSString* from my UIApplicationDelegate I get an EXC_BAD_ACCESS / NSZombie.
Is there something special I have to do to return an NSObject? Does this have to do with threading? (I thought the atomic setting on the property would take care of that?)
AppDelegate.h:
#interface AppDelegate : NSObject <UIApplicationDelegate> {
NSString * currentNoteName;
}
#property (atomic, assign) NSString *currentNoteName;
#end
AppDelegate.m:
- (void)timerCallback:(NSTimer *)timer {
currentNoteName = [NSString stringWithCString:(tone->freq).c_str() encoding:NSUTF8StringEncoding];
// This works:
NSLog(#"Current Note Name in timerCallback: %#", currentNoteName);
OtherObject.m:
// Returns a Zombie object & EXC_BAD_ACCESS:
NSString *currentNoteName = [appDelegate currentNoteName];
If not using ARC, you must using retain property:
#property (atomic, retain) NSString *currentNoteName;
and assign a value for it, using setter:
self.currentNoteName = [NSString stringWithCString: ...];
and don't forget to release instance of this ivar in your dealloc implementation of AppDelegate:
- (void) dealloc {
[currentNoteName release], currentNoteName = nil;
[super dealloc];
}
you are assigning a value and autoreleasing the NSString instance. Use retain instead.
The probleis is "assign", because the string from " [NSString stringWithCString" is auto-released.
Maybe u can change it to "copy" or "retain". (i think copy is better).