How to reference objects in NSMutableSets - objective-c

I have a small C# library that I am trying to port (actually re-writing the C# code using it as a guide) to Obj-C. The purpose of the library is to generate recurring appointments for an iOS calendar app. I'm having problems porting C# structs to Obj-C objects. This is what I have for one of the structs that holds the appointment info:
#interface Appointment : NSObject {
#public
NSDate *apptStartTime;
NSDate *apptEndTime;
NSString *key;
}
#end
One of the methods I wrote accepts a date, a set of schedules (also a port of a C# struct) and the appointment's list (I'm using a NSMutableSet which contains the Appointment interface above). If I can get the appointments method working, I'm pretty sure I can figure out the remainder (I think). This is the code that adds appointments to the NSMutableSet:
-(void) addAppointmentsForDate:(NSDate *)checkDate andSchedules: (NSMutableSet *)schedules andAppt:(NSMutableSet *)appointments {
Appointment *appt = [[Appointment alloc]init];
for(NSMutableSet *schedule in schedules) {
if(schedule.occursOnDate(checkDate)) {
appt = [self generateAppointment:checkDate andSchedule: [schedules removeObject:schedules]];
[appointments addObject: appt];
}
}
}
-(Appointment *) generateAppointment: (NSDate *) checkDate andSchedule: (Schedule *) schedule {
Appointment *appt = [[Appointment alloc]init];
appt->apptStartTime = schedule->timeOfAppointment;
appt->apptEndTime = nil; // TODO
appt->key = schedule->key;
return appt;
}
I'm getting build errors on the if statement:
Sending 'void' to parameter of incompatible type 'Schedule *'
I have never used NSMutableSets before, nor have I tried to port from C# before. I'm having a time with the port of the C# struct's, as you can see. I have read all of the Apple docs on sets, and several docs that explain the differences between C# and Obj-C.
Can somebody please either explain what I'm doing wrong, or point me to some good docs that can give me an example of referencing elements within sets?

Instead of this:
#interface Appointment : NSObject {
#public
NSDate *apptStartTime;
NSDate *apptEndTime;
NSString *key;
}
#end
please please please write
#interface Appointment : NSObject
#property (readwrite, nonatomic, strong) NSDate* startTime;
#property (readwrite, nonatomic, strong) NSDate* endTime;
#property (readwrite, nonatomic, strong) NSString* key;
#end
Don't make instance variables public. Instance variables should never, ever be accessed directly outside code belonging to that class.
Always start instance variables with an underscore character, like _startTime. That way any access to an instance variable stands out. (The code above will create instance variables for you).
Use accessors unless you have a very, very good reason not to.

Looking at the code, I have the impression that you are not quite sure whether you are writing C++ or Objective-C code.
if(schedule.occursOnDate(checkDate))
How do you call an Objective-C method again?
for(NSMutableSet *schedule in schedules)
Are you sure about this? schedules is an NSMutableSet*. So you are saying that the elements of your schedules mutable set are again mutable sets? That is quite an unusual thing to have, but if you say so...
appt = [self generateAppointment:checkDate andSchedule: [schedules removeObject:schedules]];
This is more than weird. What do you think is
[schedules removeObject:schedules]
going to do? You expect a set to have itself as an element?
My advice: Go to bed. Have ten hours of sleep. After a good breakfast, have a look at your code again.

Related

Objective-C: Property not found on object of type

So I am very new to Objective-C and I was trying to expand on a working program I made from a lesson book.
So, I have a working class names "Item". Here is Item.h:
#interface Item : NSObject
{
NSString *_itemName;
NSString *_serialNumber;
int _valueInDollars;
NSDate *_dateCreated;
}
+(instancetype)randomItem;
It has a few functions to manipulate those variables, initialize them in a costume way and print them in a formatted manner.
Then I made a sub-class of "Item" called "Container". I wanted it to be similar to "Item" but have a NSMUtableArray variable that could hold an Array of "Item"s. Here is Container.h:
#import "Item.h"
#interface Container : Item
{
NSString *_containerName;
NSDate *_containerDatecreated;
int _containerValueinDollars;
NSMutableArray *_subItems;
}
+(instancetype) randomContainer;
Now in my main. I do a number of things with the "Item" class and they work fine. But when I do this:
Container *container=[Container randomContainer];
for (NSString *item in container.containerName) {
NSLog(#"%#", item);
}
It says "Property 'containerName' not found on object of type 'Container *'". But I clearly added that variable to the "Container" subclass.
Note: randomContainer creates a random container instance and does some initializing to it. When I debug in Xcode it seems to be working fine.
What is my problem?
container.containerName is called dot syntax. It is the equivalent of [container containerName]. But you don't have a property or method on your class named containerName so the compiler is complaining.
Now, that is likely entirely baffling in the context of the book you are using. And that is because the book you are using is way way way out of date.
If it were up to date, your Item class would look more like:
#interface Item:NSObject
#property(copy) NSString *containerName;
#property(copy) NSDate *containerDateCreated;
#property(assign) NSInteger containerValueInDollars;
... etc ...
#end
Get yourself an up to date set of tutorials and/or books before learning anything else. It'll save a lot of frustration.

Subclassing iOS Model Objects - Appropriate Design Pattern

I fear this is a rather simple question, but after much googling I think I have overshot my intended result. I believe my question to be related to a design pattern, but alas I could be wrong.
My application calls an RESTful API and gets back what amounts to a list of model objects represented by an NSDictionary. Each of which I will call NNEntity. There are (conceptually) multiple different subtypes of NNEntity. All subtypes of NNEntity share the property of entityID, but each have their own unique properties as well. All instances of NNEntity have a method called readFromDict:(NSDictionary *)d that populates their respective properties. This method is enforced by a protocol that all NNEntity subtypes conform to. It looks like this:
//NNEntity.h
#interface NNEntity : NSObject <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *entityID;
#end
//NNEntity.m
#implementation NNEntity
- (void)readFromDict:(NSDictionary *)d {
//set common properties from values in d
self.entityID = [d objectForKey:#"ID"];
}
#end
//NNSubEntity1.h
#interface NNSubEntity1 : NSEntity <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *favoriteColor;
#end
//NNSubEntity1.m
#implementation NNSubEntity1
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.favoriteColor = [d objectForKey:#"colorPreference]:
}
#end
//NNSubEntity2.h
#interface NNSubEntity2 : NSEntity <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *middleName;
#end
//NNSubEntity2.m
#implementation NNSubEntity2
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.middleName = [d objectForKey:#"middleName]:
}
#end
I have read various pieces on the use of a Factory or Builder Desing pattern for similar use cases but I am curious if that is necessary in this rather simple case. For example, does my current code end up creating both and instance of NNEntity and NNSubEntity2 if I were to call something like this:
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];
I assume not, but would newEntity have both the common property of entityID as well as the unique property of middleName set correctly? Also, much appreciated if you have thoughts on a better or more efficient design approach.
This looks like exactly how you should be doing it. You have a base class which read in the common attributes, and subclasses which read in their specific attributes.
For example, does my current code end up creating both and instance of NNEntity and NNSubEntity2? NNEntity *newEntity = [[NNSubEntity2 alloc] init];
Nope. When you run this, you instantiate NNSubEntity2 and store the result in a variable typed by it's superclass, which is totally valid. This allows you to call any methods defined on the superclass, but the actual instance is still of the subclass.
Would newEntity have both the common property of entityID as well as the unique property of middleName set correctly?
It sure would. It inherits the instance variables, properties and methods in the superclass.
Rest assured, as far as I can tell this looks sound and is a pattern I've used before.
I do it like this.
// NNEntity.h
#interface NNEntity : NSObject
#property (nonatomic, retain) NSString *entityId;
#end;
// NNEntity.m
#implementation NNEntity
#end;
// NNEntity+KVC.h
#interface NNEnity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
#end
// NNEntity+KVC.m
#implementation NNEntity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// Handle this as appropriate to your app.
// A minimal implementation will throw an exception.
}
#end
And similarly for your various subclasses. You don't (necessarily) need the category on your subclasses.
Then, given NSDictionary *dict with your stuff in it:
NNEntity *entity = [[NNEntity alloc] init];
[entity setValuesForKeysWithDictionary:dict];
Violá! You're done. There are some criticisms of this method, but given a strong implementation of setValue:forUndefinedKey:, I think it's safe and incredibly flexible.
The secrets are in Apple's beautiful Key-Value Coding technology. Essentially, setValuesForKeysWithDictionary: iterates the keys the dict you give it, and for eachinvokes setValue:forKey: in its receiver. It looks something like this (though I'm sure Apple optimizes it under the hood):
-(void)setValuesForKeysWithDictionary:(NSDictionary *)dictionary {
NSArray *keys = [dictionary allKeys];
for (NSString* key in keys) {
[self setValue:[dictionary valueForKey:key] forKey:key];
}
}
I also like this approach because a conversion to CoreData is simple; when you tell CoreData to 'render' your model, it simply overwrites your stubbed model classes, keeping your KVC Category intact. What is more, if your implementation of setValue:forUndefinedKey: is smooth, you can make model changes to your backend without crashing the app (this is a bit of a no-no, but it's not much different from your factory solution).
Of course, I have not addressed your need to selectively choose which class to instantiate. But that is a larger design issue that could be affected even by the design of your API and backend. So I defer.
Also, as you noted in your comment below, the property names must match up. This is a show-stopper for some developers, especially so if you cannot control both the backend and the client.
Give it a try. Feedback is welcome.

Accessing Objects from Class or Method

I have 2 classes in my Cocoa project (Xcode). First is AppDelegate class and the second is a Book class.
In my Book class, I set an integer property in the #interface which is the book's chapters. In its #implementation, I have created objects (ex. Book *firstBook = [[Book alloc]init]) and set their properties (In the Book.m file). Those are my data and will not change.
In my app delegate, I have a method that will fetch what the user selected from an interface item, get the title of the selected item, who's name will be identical to one of those in Book.m. Then a for loop will run to create menu items for a popUpButton so the user can select which chapter to jump to.
The problem I am seeing now is that when I try running the for loop to create menu items, I need the limit amount of the loops. That limit amount is based on the selectedObjectByUser's chapter property (listed in Book.m). How do I access that.
I am sure it will work if I can connect these two together because it works when create the object inside this method(under AppDelegate.h) but the problem is that it is too space consuming and it changes often.
I'm not entirely sure what the situation is here, but let's take a look at some sample code first.
//// Book.h
#interface Book : NSObject
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *author;
#property (nonatomic, assign) NSInteger numberOfPages;
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor;
#end
//// Book.m
#implementation Book
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor {
if ( self = [super init] ) {
self.title = aTitle;
self.author = anAuthor;
}
return self;
}
- (void)dealloc {
self.title = nil;
self.author = nil;
[super dealloc];
}
#end
So in this we establish a class and provide it with 3 properties, title and author (which are both NSString's) and numberOfPages (which is an integer). Within the class we can manipulate those values by calling things such as self.propertyName = value.
This is all well and good, but what actually is happening? Well let's update the header a little more:
//// Book.h
#interface Book : NSObject {
#private
NSString *_title;
NSString *_author;
NSInteger _numberOfPages;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *author;
#property (nonatomic, assign) NSInteger numberOfPages;
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor;
#end
In this, we have just explicitly defined something that the compiler will normally infer through the #property construct. These new additions are what we call instance variables, or ivars, and are where the values you assign to your properties are actually stored.
However, manipulating the ivars can be dangerous if you are not yet 100% comfortable with memory management. Even if you are using ARC, you should still understand how that management works.
So we've now exposed where these properties actually store there data, but what about that #private job? What's it all about? #private is part of a family of keywords that help to denote the "Accessibility Scope" of something. The other two keywords in this family are #protected and #public, however the use of the second two is infrequent, if not unusual. These keywords are responsible for saying where you are allowed to access things. Here's a quick definition of them.
#public Freely accessible from anywhere, even outside of the object itself. However accessing an instance variable directly from outside of its own class is generally considered to be extremely bad practice in the Cocoa development world, hence why you'll find very little on how to do it.
#protected Freely accessible within the class and its own subclasses. Can not be accessed outside of the class/object.
#private Freely accessible within the class, but not anywhere else. Can not be accessed outside of the class/object or even in its subclasses.
So now that we've covered what is actually driving the storage behind a property, let's take a look at using our Book object in another part of the app, such as AppDelegate.
//// AppDelegate.m
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
Book *myBook = [[Book alloc] initWithTitle:#"pending title" andAuthor:#"Foo Bar"];
myBook.title = #"My Cool Book";
NSLog(#"%# by %#", myBook.title, myBook.author);
[myBook release];
}
#end
In this we create a new Book object, to put it in more technical terms, we define a variable called myBook with a type of Book and instantiate it. In this we're using the -initWithTitle:andAuthor: method that we created earlier in order to tell the Book object that it should have an initial title and author.
Following this line we then arrive something a little more curious. myBook.title = #"My Cool Book"; You might recall that we had something similar back in Book.m, self.title = aTitle. So what is going on here? Why are we using myBook now rather than self, like we did previously? The reason is because of what self actually is.
self is a keyword provided by the Objective-C runtime, and refers to the current object that you are within. So if we write code inside Book.m, self will refer to the current Book object. If we use self within AppDelegate.m, it will refer to the AppDelegate. So in our earlier code, self was referring to the current Book object much like our myBook object is now referring to a specific Book object. They essentially are equal to each other (not exactly, but thats another area of discussion).
This means any of the properties within Book or methods can be accessed through the myBook variable, much like you would using self inside of Book.m. So we could also do
myBook.title = #"My Book";
myBook.author = #"Baz Quux";
myBook.numberOfPages = 100;
Hope this helps (and answered your question, if not then may it serve as a reference to people wishing to know more about properties and instance variables)

Is there any reason to declare ivars if you're using properties exclusively in Objective-C?

I tend to use properties exclusively in my classes, especially now that you can declare properties in a class extension thanks to the modern Objective-C 2.0 runtime—I use this feature to create "private" properties.
My question is if there is any good reason to ever declare ivars in a class interface anymore. I prefer my public-facing interfaces to be as minimal and clean as possible, only revealing aspects of my class that are pertinent.
For example, I would tend to do the following:
MyClass.h:
#interface MyClass : NSObject
#property (nonatomic, copy) NSString * publicString;
#property (nonatomic, copy, readonly) NSString * readOnlyString;
#end
MyClass.m:
#interface MyClass ()
#property (nonatomic, copy, readwrite) NSString * readOnlyString;
#property (nonatomic, copy) NSString * privateString;
#end
#implementation MyClass
#synthesize publicString = publicString_;
#synthesize readOnlyString = readOnlyString_;
#synthesize privateString = privateString_;
- (void)init
{
self = [super init];
if (self != nil)
{
self.publicString = #"Public String";
self.readOnlyString = #"Read-Only String";
self.privateString = #"Private String";
}
return self;
}
- (void)dealloc
{
[publicString_ release];
[readOnlyString_ release];
[privateString_ release];
[super dealloc];
}
#end
Code style preferences aside, are there any issues with avoiding ivars entirely like this?
I may have found an answer that's suitable enough for me to explicitly back my properties with ivars. It doesn't appear as if the debugger will list any automatically synthesized ivars, so there's no way to just drill through self during debugging and check various values other than manually calling the property accessors, which is tedious. Unless they change this, this is probably more than enough reason for me to just go back to declaring ivars explicitly.
The main issue, if it bothers you at all, is that per Cocoa With Love, dynamic instance variables such as those you're using aren't supported by runtimes other than those for 64bit Intel/PowerPC (fixed per Chuck's comment below) and ARM (for iOS).
I'm not currently able to find an authoritative Apple document on the issue; note that restricting to the latest OS X, v10.6, is not sufficient since it is available for and supported on the 32bit Intel machines that Apple shipped immediately after switching from PowerPC.
Late extra thought: without knowing about any potential changes in Xcode 4, a good reason to declare otherwise private instance variables within the header file is to mark them as IBOutlets and wire them up graphically. That's really only relevant to a very specific type of class and member variable though, admittedly.
I have to agree with LucasTizma on the debugging issue.
When I began using XCode4, I started not explicitly declaring ivars and let them be created for me using #synthesize aVar = _aVar syntax. While trying to debug code, I noticed that I couldn't hover the cursor over the variable and see its value.
For me, this is just unacceptable. I guess it's back to declaring them explicitly.
Beyond Tommy's concern, declaring an ivar is certainly good practice, especially if your code might be reused or if you might come back to your code sometime.

How to ensure no memory leak for Objective-C class that is called by many other class

I have the following controller class which will do different tasks based on combination of the flag and param property. The value of these two properties will be set by many other classes having a reference to this controller. The question is how does each of the calling class assign value and when should they release it so that there will be no memory leak ?
#interface SampleController {
NSMutableArray *param;
NSString *flag;
}
#property (nonatomic, retain) NSMutableArray *param;
#property (nonatomic, retain) NSString *flag;
#end
#implementation SampleController
#synthesize param;
#synthesize flag;
- (id)init
{
param = [[NSMutableArray alloc] initWithCapacity:0];
flag = #"nothing";
}
#end
Well it depends on how you call your controller :
in an instance variable of an other object : you have to release it in this object's deallocate methode
in a function : you should release it when you do not need it anymore (retained by another object for example or it finished the job in this function), if you want to return it, just sent the message "autorelease" to it and the NSAutoReleasePool will do the job for you.
To assign value, you can
set the mutable array with the setParam:(*NSMutableArray)theArrayYouWantToReplaceYourArrayWith
access it directly with [[yourSampleController param]addObject:(id)objectYouWantToAdd]...
or more convenient : [yourSampleController.param addObject:(id)objectYouWantToAdd]
The addObject: message here is an example, you can see the methods for modifying an array (remove, sort,...) in the NSMutableArray class reference.
You will not be able to modify your string since it is a NSString and not a NSMutableString, but you can accessit by
[yourSampleController getParam]
[yourSampleController param]
yourSampleController.param
If you want to avoid leaks in general, build your project with the Instrument tool in leak mode and look at the objects that are leaked if you found some that are declared in your functions.
You can also check the Clang Static Analyzer (free static debugger) which is quite good if you have a lot of files.
I hope i helped you
Julien