It means you are missing a framework.
Look for the method name in the error. In my case it was some CAAnimation call used by a class. CAAnimation is used by the framework QuartzCore. Hence by adding QuartzCore framework, I solved this issue.
It means you are missing a framework.
Look for the method name in the error. In my case it was some CAAnimation call used by a class. CAAnimation is used by the framework QuartzCore. Hence by adding QuartzCore framework, I solved this issue.
In your init
1 2 3 4 |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addImage:) name:INSERT_EVENT_IMAGE object:nil]; |
what to do when the message is sent
1 2 3 4 5 6 7 8 9 10 11 |
-(void)addImage:(NSNotification*)notification { if([[notification name] isEqualToString:INSERT_EVENT_IMAGE]) { NSDictionary *userInfo = notification.userInfo; UIImage * image = [userInfo objectForKey:@"image"]; // your code } } |
Sending the message
1 2 3 4 5 6 7 |
NSDictionary * packet = @{ @"image" : image }; [[NSNotificationCenter defaultCenter] postNotificationName:INSERT_EVENT_IMAGE object:self userInfo:packet]; |
When adding observers to receive notifications for a certain unique id, we can choose which object to receive it from. In our example below, we have method sexGroupUpdated: which will be executed once the notification is received for unique id SELECTED_RADIO_BUTTON_CHANGED. But we only will do this IFF those notifications are sent from self.sexGroup object.
1 |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sexGroupUpdated:) name:SELECTED_RADIO_BUTTON_CHANGED object:self.sexGroup]; |
Extending our example, let’s say in our MainView.m, we have multiple objects of the same class TNRadioButtonGroup created. Those classes all send SELECTED_RADIO_BUTTON_CHANGED unique id notifications. We can differentiate which methods the notifications will hit by putting the name of the objects that are sending those notifications:
1 2 3 4 5 6 7 8 9 10 11 12 |
self.sexGroup = [[TNRadioButtonGroup alloc] initWithRadioButtonData:@[maleData, femaleData, alienData] layout:TNRadioButtonGroupLayoutHorizontal]; //blah blah [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sexGroupUpdated:) name:SELECTED_RADIO_BUTTON_CHANGED object:self.sexGroup]; self.hobbiesGroup = [[TNRadioButtonGroup alloc] initWithRadioButtonData:@[snowboardData,tennisData, programmingData] layout:TNRadioButtonGroupLayoutVertical]; ...blah blah.... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hobbiesGroupUpdated:) name:SELECTED_RADIO_BUTTON_CHANGED object:self.hobbiesGroup]; self.temperatureGroup = [[TNRadioButtonGroup alloc] initWithRadioButtonData:@[coldData, hotData, hotData1, hotData2] layout:TNRadioButtonGroupLayoutHorizontal]; ...blah blah.... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(temperatureGroupUpdated:) name:SELECTED_RADIO_BUTTON_CHANGED object:self.temperatureGroup]; |
Sending of those notifications as shown TNRadioButtonGroup.m:
1 2 3 4 5 6 7 8 9 |
- (void)setSelectedRadioButton:(TNRadioButton *)selectedRadioButton { if( _selectedRadioButton != selectedRadioButton ){ _selectedRadioButton = selectedRadioButton; [[NSNotificationCenter defaultCenter] postNotificationName:SELECTED_RADIO_BUTTON_CHANGED object:self]; } } |
It posts notification for constant string SELECTED_RADIO_BUTTON_CHANGED.
Let’s analyze in detail.
In our MainView.m, we’re adding an observer for notifications for string id SELECTED_RADIO_BUTTON_CHANGED.
But we’re getting it from three different instantiations of TNRadioButtonGroup:
sexGroup, hobbiesGroup, and temperatureGroup. They all send a notifications of id SELECTED_RADIO_BUTTON_CHANGED.
In other words, sexGroup, hobbiesGroup, and temperatureGroup all send those notifications. How do we differentiate them?
That’s where the paramter object comes in. As you noticed, we specified the object variable in which we receive these notifications:
1 |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(temperatureGroupUpdated:) name:SELECTED_RADIO_BUTTON_CHANGED object:self.temperatureGroup]; |
It simply means we will execute temperatureGroupUpdated: when we receive SELECTED_RADIO_BUTTON_CHANGED notifications, but only from the object self.temperatureGroup.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
UITextField * username = [ [ UITextField alloc ] initWithFrame:CGRectMake( 200, 10.0f, 100.0f, 32.0f ) ]; username.tag = CREATEUSER_UITEXTFIELD_USERNAME; username.borderStyle = UITextBorderStyleRoundedRect; username.textColor = [UIColor blackColor]; username.font = [UIFont systemFontOfSize:20.0]; username.keyboardType = UIKeyboardTypeDecimalPad; username.returnKeyType = UIReturnKeyDone; username.clearButtonMode = UITextFieldViewModeWhileEditing; username.delegate = self; [username setBackgroundColor:[UIColor blueColor]]; [username setTextAlignment:NSTextAlignmentCenter]; //To make the border look very close to a UITextField [username.layer setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor]]; [username.layer setBorderWidth:1.0]; [username.layer setCornerRadius:18.0f]; username.placeholder = @"BBT"; username.textAlignment = NSTextAlignmentCenter; username.autocapitalizationType = UITextAutocapitalizationTypeNone; |
when using PopUpViewcontroller, make sure the variable you assign to it has property strong so that it doesn’t get released.
Else, you’ll get a EXE_ACCESS error.
Notice below of self.singleColPickerPopup:
1 2 3 4 5 6 7 8 9 10 |
if(plistPath) { dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; dataArray = dict ? [NSArray arrayWithArray:[dict objectForKey:@"PhysicalExperiences"]] : nil ; //return [[PopUpViewController alloc] initWithChoicesType:type andParameters:dataArray andUnitLabel:unit]; self.singleColPickerPopup = [[SingleColumnPopupPickerViewController alloc] initWithParameters:dataArray andUnitLabel:@"" andIsDigit:NO]; [self.singleColPickerPopup showInView:rootView withImage:nil withMessage:cell.textLabel.text animated:YES]; } |
1 2 3 4 5 6 |
-(NSString*)stringFromNSDate:(NSDate*)date { NSDateFormatter * formatterExisting = [[NSDateFormatter alloc]init]; [formatterExisting setDateFormat:@"yyyy-MM-dd"]; return [formatterExisting stringFromDate:date]; } |
1 2 3 |
NSIndexPath *fifthRow = [NSIndexPath indexPathForRow:4 inSection:0]; UITableViewCell *cell = [tableView cellForRowAtIndexPath:fifthRow]; cell.textLabel.text = @"the updated text"; |
JSCustomCell.h
1 2 3 4 5 6 7 8 9 |
@interface JSCustomCell : UITableViewCell { } // now only showing one label, you can add more yourself @property (nonatomic, strong) UILabel *descriptionLabel; @end |
JSCustomCell.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@implementation JSCustomCell @synthesize descriptionLabel = _descriptionLabel; - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // configure control(s) self.descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 10, 300, 30)]; [self.descriptionLabel setBackgroundColor:[UIColor redColor]]; self.descriptionLabel.textColor = [UIColor blackColor]; self.descriptionLabel.font = [UIFont fontWithName:@"Arial" size:12.0f]; [self addSubview:self.descriptionLabel]; [self setBackgroundColor:[UIColor orangeColor]]; } return self; } @end |
result:
ViewController.h
1 2 |
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> @end |
ViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#import "ViewController.h" #import "JSCustomCell.h" @interface ViewController () @property(nonatomic, strong) UITableView *tableView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // init table view self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; // must set delegate & dataSource, otherwise the the table will be empty and not responsive self.tableView.delegate = self; self.tableView.dataSource = self; self.tableView.backgroundColor = [UIColor cyanColor]; // add to canvas [self.view addSubview:self.tableView]; } #pragma mark - UITableViewDataSource // number of section(s), now I assume there is only 1 section - (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView { return 1; } // number of row in the section, I assume there is only 1 row - (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section { return 1; } // the cell will be returned to the tableView - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"HistoryCell"; // Similar to UITableViewCell, but JSCustomCell *cell = (JSCustomCell *)[theTableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[JSCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; } // Just want to test, so I hardcode the data cell.descriptionLabel.text = @"Testing"; return cell; } #pragma mark - UITableViewDelegate // when user tap the row, what action you want to perform - (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"selected %d row", indexPath.row); } @end |
reference: http://stackoverflow.com/questions/1406037/custom-animation-for-pushing-a-uiviewcontroller
In the parent view controller, you have a button that brings in the a UIViewController. In your button responder, you go:
1 2 3 4 5 6 7 8 |
-(void)onLogButtonTouch:(UIBarButtonItem *)sender { NSLog(@"on log button press"); LogViewController * logViewController = [[LogViewController alloc] init]; [self.navigationController pushViewController:logViewController animated:NO]; } |
In the UIViewController:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
-(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:YES]; [UIView transitionFromView:self.parentViewController.view toView:self.view duration:0.5f options:UIViewAnimationOptionTransitionCurlDown completion:^(BOOL finished) { // Do something... or not... }]; } |
I use the following function (added to UINavigationController) to customize the push animation:
1 2 3 4 5 6 7 8 9 10 |
- (void) pushController: (UIViewController*) controller withTransition: (UIViewAnimationTransition) transition { [UIView beginAnimations:nil context:NULL]; [self pushViewController:controller animated:NO]; [UIView setAnimationDuration:.5]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationTransition:transition forView:self.view cache:YES]; [UIView commitAnimations]; } |
ref: http://stackoverflow.com/questions/4089238/implementing-nscopying
To implement NSCopying, your object must respond to the -copyWithZone: selector. Here’s how you declare that you conform to it:
1 |
@interface MyObject : NSObject <NSCopying> { |
Then, in your object’s implementation (your .m file):
1 2 3 4 |
- (id)copyWithZone:(NSZone *)zone { // Copying code here. } |
What should your code do? First, create a new instance of the object—you can call [[[self class] alloc] init] to get an initialized obejct of the current class, which works well for subclassing. Then, for any instance variables that are a subclass of NSObject that supports copying, you can call [thatObject copyWithZone:zone] for the new object. For primitive types (int, char, BOOL and friends) just set the variables to be equal. So, for your obejct Vendor, it’d look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
- (id)copyWithZone:(NSZone *)zone { id copy = [[[self class] alloc] init]; if (copy) { // Copy NSObject subclasses [copy setVendorID:[[self.vendorID copyWithZone:zone] autorelease]]; [copy setAvailableCars:[[self.availableCars copyWithZone:zone] autorelease]]; // Set primitives [copy setAtAirport:self.atAirport]; } return copy; } |
http://stackoverflow.com/questions/4472904/implementing-nscopying-in-subclass-of-subclass?rq=1
http://stackoverflow.com/questions/18673296/overriding-readonly-property-in-subclass
The base is class is straightforward. We only have two member variables, but do not want others to access them. So we declare readonly in @property in the .h file. However, we DO want to modify them in our own implementation. We declare readwrite in our @property in the .m file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@interface Today : NSObject <NSCopying> { @protected NSNumber * dayPerformance_PlacingCount; NSNumber * dayPerformance_PlacingAmount; } //how will it be accessed outside @property(atomic, readonly) NSNumber * dayPerformance_PlacingCount; @property(atomic, readonly) NSNumber * dayPerformance_PlacingAmount; -(id)init; -(id)initWithCount:(NSNumber*)count andAmount:(NSNumber*)amount; -(float) getAverage ; @end |
Notice the @protected above the member variables. I did this so that children classes can access these member variables.
1 2 3 4 5 6 |
@interface Today() @property(atomic, retain, readwrite) NSNumber * dayPerformance_PlacingCount; @property(atomic, retain, readwrite) NSNumber * dayPerformance_PlacingAmount; @end |
Be sure to synthesize them. Its basically getter/setter = iVar
1 2 3 4 5 6 7 |
@implementation Today // getter,setter = iVar @synthesize dayPerformance_PlacingCount; // getter,setter = iVar @synthesize dayPerformance_PlacingAmount; |
In our case, since we we did not specify an iVar like this:
1 |
@synthesis variableName = _variableName |
dayPerformance_PlacingCount is the iVar
and
1 |
self.dayPerformance_PlacingCount |
makes it run through the setter/getter methods.
So the idea behind copyWithZone is that we need to make a deep copy. Hence everything should have its own address. Staying true to that assertion, we must first dynamically allocate the object to be returned:
1 |
id copy = [[[self class] alloc] init]; |
We create an empty self class. But wait, What about its member variables? They need to be unique with their own address. So we dynamically create those member variables like so:
1 2 |
NSNumber * tempCount = [NSNumber numberWithFloat:[self.dayPerformance_PlacingCount floatValue]]; NSNumber * tempAmount = [NSNumber numberWithFloat:[self.dayPerformance_PlacingAmount floatValue]]; |
Then we have our newly created object’s member variables retain them. the variable copy is our newly created Day variable:
1 2 |
[copy setDayPerformance_PlacingAmount:tempAmount]; [copy setDayPerformance_PlacingCount:tempCount]; |
..and then we just return that copy variable.
thus, it gets returned like so:
1 2 3 4 |
Day * myDay = [Day alloc] init]; Day * yourDay = [myDay copy]; ... ... |
Thus, yourDay takes on a whole newly allocated Day instance with its own member variables and all.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
//DEEP COPY: everyone has their own address - (id)copyWithZone:(NSZone *)zone { DLOG(@"Today.m - copyWithZone"); // Copying code here. DLOG(@"Deep Copy, alloc/init Base class"); Day * copy = [[[self class] alloc] init]; if (copy) { DLOG(@"Today.m - copy is valid"); //first let's create our own objects with unique addresses //all auto released NSNumber * tempCount = [NSNumber numberWithFloat:[self.dayPerformance_PlacingCount floatValue]]; NSNumber * tempAmount = [NSNumber numberWithFloat:[self.dayPerformance_PlacingAmount floatValue]]; //you can also do this: //[[[NSNumber alloc] initWithFloat:[self.dayPerformance_PlacingAmount floatValue]] autorelease] DLOG(@"Today.m - deep copying instance varaibles"); //have our iVars retain on them [copy setDayPerformance_PlacingAmount:tempAmount]; [copy setDayPerformance_PlacingCount:tempCount]; DLOG(@"Today.m - In Today, placing amount is: %@", [[copy dayPerformance_PlacingAmount] stringValue]); DLOG(@"Today.m - In Today, placing count is: %@", [[copy dayPerformance_PlacingCount] stringValue]); } DLOG(@"returning alloc'ed Base class"); return copy; } |
To use it in your main, you go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Today * dayOne = [[Today alloc] initWithCount:[NSNumber numberWithFloat:609.00] andAmount:[NSNumber numberWithFloat:1204.50]]; DLOG(@"~~~~~~~~dayOne~~~~~~~~~~~~~"); DLOG(@"dayOne's address: %p", dayOne); DLOG(@"dayPerformance_PlacingAmount address: %p",dayOne.dayPerformance_PlacingAmount); DLOG(@"dayPerformance_PlacingAmount value: %f",[dayOne.dayPerformance_PlacingAmount floatValue]); DLOG(@"~~~~~~~~~~~~~~~~~~~~~"); Today * dayTwo = [dayOne copy]; DLOG(@"~~~~~~~~dayTwo~~~~~~~~~~~~~"); DLOG(@"dayTwo's address: %p", dayTwo); DLOG(@"dayPerformance_PlacingAmount's address: %p",dayTwo.dayPerformance_PlacingAmount); DLOG(@"dayPerformance_PlacingAmount's value: %f",[dayTwo.dayPerformance_PlacingAmount floatValue]); DLOG(@"~~~~~~~~~~~~~~~~~~~~~"); |
Result:
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 58] – ~~~~~~~~dayOne~~~~~~~~~~~~~
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 59] – dayOne’s address: 0x16dc1f80
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 60] – dayPerformance_PlacingAmount address: 0x16dc1fa0
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 61] – dayPerformance_PlacingAmount value: 1204.500000
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 62] – ~~~~~~~~~~~~~~~~~~~~~
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 66] – ~~~~~~~~dayTwo~~~~~~~~~~~~~
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 67] – dayTwo’s address: 0x16dc22a0
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 68] – dayPerformance_PlacingAmount’s address: 0x16dc22e0
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 69] – dayPerformance_PlacingAmount’s value: 1204.500000
-[AppDelegate application:didFinishLaunchingWithOptions:] [Line 70] – ~~~~~~~~~~~~~~~~~~~~~
As you can see, the Day addresses are different from the copy. As well as the member variables. In this particular case, I only printed out instance variable dayPerformance_PlacingAmount.
Fast enumeration is an Objective-C’s feature that helps in enumerating through a collection.
Collections in Objective-C
Collections are fundamental constructs. It is used to hold and manage other objects. The whole purpose of a collection is that it provides a common way to store and retrieve objects efficiently.
There are several different types of collections. While they all fulfil the same purpose of being able to hold other objects, they differ mostly in the way objects are retrieved. The most common collections used in Objective-C are:
NSSet
NSArray
NSDictionary
NSMutableSet
NSMutableArray
NSMutableDictionary
Fast enumeration Syntax
for (classType variable in collectionObject )
{
statements
}
Here is an example for fast enumeration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#import <Foundation/Foundation.h> int main() { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSArray *array = [[NSArray alloc] initWithObjects:@"string1", @"string2",@"string3",nil]; for(NSString *aString in array) { NSLog(@"Value: %@",aString); } [pool drain]; return 0; } |