in my new App I have Core Data and Magical Record and this is how is structured the db:
This is the class corresponding to the entity NEWS:
#class SMCategories;
#interface SMNews : NSManagedObject
#property (nonatomic, retain) NSNumber * wpId;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSString * content;
#property (nonatomic, retain) NSString * url;
#property (nonatomic, retain) NSString * thumbnailUrl;
#property (nonatomic, retain) NSString * thumbnailFile;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) SMCategories *category;
This is the class corresponding to the entity CATEGORIES:
#interface SMCategories : NSManagedObject
#property (nonatomic, retain) NSNumber * wpId;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSDate * lastUpdate;
#property (nonatomic, retain) NSSet *news;
#end
#interface SMCategories (CoreDataGeneratedAccessors)
- (void)addNewsObject:(NSManagedObject *)value;
- (void)removeNewsObject:(NSManagedObject *)value;
- (void)addNews:(NSSet *)values;
- (void)removeNews:(NSSet *)values;
This is the function I use to save, inside a cycle, all the datas that should be saved in the entity CATEGORIES:
- (void)saveUpdateCategories:(NSString *)result {
NSDictionary *tmpCategories = [result objectFromJSONString];
NSArray *categoriesList = [tmpCategories objectForKey:#"categories"];
NSDictionary *singleCategory;
NSPredicate * filter = [[NSPredicate alloc] init];
for(int i = 0; i < [categoriesList count];i++) {
singleCategory = [categoriesList objectAtIndex:i];
filter = [NSPredicate predicateWithFormat:#"wpId == %#",[singleCategory objectForKey:#"id"]];
SMCategories *checkCategory = [SMCategories MR_findFirstWithPredicate:filter];
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
SMCategories *categoryToAdd;
if (checkCategory == nil) {
categoryToAdd = [SMCategories MR_createEntityInContext: localContext];
} else {
categoryToAdd = checkCategory;
}
categoryToAdd.name = [singleCategory objectForKey:#"name"];
categoryToAdd.wpId = [currentUtils stringToNumber:[singleCategory objectForKey:#"id"]];
categoryToAdd.lastUpdate = [currentUtils stringToDate:#"01/01/2000 00:00:01" formatted:#"dd/MM/yyyy HH:mm:ss"];
categoryToAdd.news = nil;
} completion:^(BOOL success, NSError *error) {
if (i == [categoriesList count] - 1) {
[progressWheel stopAnimating];
NSMutableDictionary *tmpOptions = [[NSMutableDictionary alloc] init];
tmpOptions = [currentUtils getDictionaryPlistFile:#"options.plist" path:[currentUtils getMainLocalPath]];
[tmpOptions setObject:[NSDate date] forKey:#"lastCategoriesUpdates"];
[currentUtils saveDictionaryPlistFile:tmpOptions fileName:#"options.plist" path:[currentUtils getMainLocalPath]];
[menuButton setEnabled:YES];
if (categoryToLoadPassed == nil)
categoryToLoadPassed = [SMCategories MR_findFirstByAttribute:#"name" withValue:DEFAULT_CATEGORY];
[self downloadNewsOfCategory:categoryToLoadPassed];
}
}];
}
}
This part of code works as well.
This is the funcion I use to save, inside another cycle, all the datas that should be inserted into the entity NEWS.
-(void) saveNewsOfCategory:(SMCategories *)category resultToSave: (NSString *) result {
NSDictionary *tmpNews = [result objectFromJSONString];
NSArray *newsList = [tmpNews objectForKey:#"posts"];
NSDictionary *singleNew;
NSPredicate * filter = [[NSPredicate alloc] init];
for(int i = 0; i < [newsList count];i++) {
singleNew = [newsList objectAtIndex:i];
filter = [NSPredicate predicateWithFormat:#"wpId == %#",[singleNew objectForKey:#"id"]];
SMNews *checkNew = [SMNews MR_findFirstWithPredicate:filter];
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
SMNews *newToAdd;
if (checkNew == nil) {
newToAdd = [SMNews MR_createEntityInContext: localContext];
} else {
newToAdd = checkNew;
}
newToAdd.category = category;
newToAdd.title = [singleNew objectForKey:#"title"];
newToAdd.content = [singleNew objectForKey:#"content"];
newToAdd.wpId = [currentUtils stringToNumber:[singleNew objectForKey:#"id"]];
newToAdd.date = [currentUtils stringToDate:[singleNew objectForKey:#"date"] formatted:#"yyyy-MM-dd HH:mm:ss"];
newToAdd.url = [NSString stringWithFormat:#"%#?p=%#",WEBSITE,[singleNew objectForKey:#"id"]];
newToAdd.thumbnailFile = nil;
newToAdd.thumbnailUrl = [singleNew objectForKey:#"image"];
} completion:^(BOOL success, NSError *error) {
if (i == [newsList count] - 1) {
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
category.lastUpdate = [NSDate date];
} completion:^(BOOL success, NSError *error) {
[progressWheel stopAnimating];
[currentTable reloadData];
}];
}
}];
}
}
Here it's thrown an exception EXT_BAD_ACCESS next to the line
newToAdd.category = category;
category is passed as one of the parameters of the corresponding function.
As you would have understood I have 2 entitis CATEGORIES and NEWS with a One-To-Many relationship.
First off I download all the categories and I store them into CATEGORIES entity when the user wants to download all the news of a specific category I download them and store with the second function into news entity passign into the second function the category of those specific news as parameters of my function.
If delete the line incriminated all the news are correctly store inside the database but they are not related to any cateogries.
What am I doing wrong?
The following line that threw an exception because I save the entity in a new Thread.
newToAdd.category = category;
So used a singleton class to get the category and set in that specific localcontex this way
SMCategories *currentCategory = [[DataManager getInstance] getCurrentCategory];
newsToAdd.category = [currentCategory MR_inContext:localContext];
Now everything works correctly.
Related
I found how to implement a searchBar, but I don't know what to do in updateSearchResultsForSearchController method. All my data is fetched from CoreData. Here I put my code. If anyone had similar problem please tell me what to do.
#interface PlumbListTableViewController ()<NSFetchedResultsControllerDelegate, UIPageViewControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating, UISearchControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong) NSArray *array;
#property (nonatomic, strong) NSNumber *number;
#property (nonatomic) int sum;
#property (nonatomic, strong) PickerViewController *picker;
#property (nonatomic, strong) UISearchController *searchController;
#property (nonatomic, strong) NSMutableArray *fileteredTableData;
#property (nonatomic, strong) NSArray *products;
#property (nonatomic, strong) NSArray *recipies;
#property (nonatomic, strong) NSArray *searchResults;
#end
#implementation PlumbListTableViewController
-(void)viewDidLoad {
[super viewDidLoad];
//All data from CoreData
self.products = [Product allProducts];
self.searchResults = [NSMutableArray arrayWithCapacity:[self.products count]];
[self.fetchedResultsController performFetch:nil];
CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"AddEntry"];
fetchRequest.resultType = NSDictionaryResultType;
self.recipies = [coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
}
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
[self initializeSearchController];
self.tabBarController.tabBar.hidden = NO;
[self showTotalSum];
[self.tableView reloadData];
}
-(void)initializeSearchController {
//instantiate a search results controller for presenting the search/filter results (will be presented on top of the parent table view)
UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
searchResultsController.tableView.dataSource = self;
searchResultsController.tableView.delegate = self;
//instantiate a UISearchController - passing in the search results controller table
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
//this view controller can be covered by theUISearchController's view (i.e. search/filter table)
self.definesPresentationContext = YES;
//define the frame for the UISearchController's search bar and tint
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
self.searchController.searchBar.tintColor = [UIColor whiteColor];
//add the UISearchController's search bar to the header of this table
self.tableView.tableHeaderView = self.searchController.searchBar;
//this ViewController will be responsible for implementing UISearchResultsDialog protocol method(s) - so handling what happens when user types into the search bar
self.searchController.searchResultsUpdater = self;
//this ViewController will be responsisble for implementing UISearchBarDelegate protocol methods(s)
self.searchController.searchBar.delegate = self;
}
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"edit"]) {
UITableViewCell *cell = sender;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
UINavigationController *navigationController = segue.destinationViewController;
PlumbAddViewController *entryViewController = (PlumbAddViewController *)navigationController.topViewController;
entryViewController.entry = [self.fetchedResultsController objectAtIndexPath:indexPath];
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return self.fetchedResultsController.sections.count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
return [sectionInfo numberOfObjects];
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
ConfigureCellPlumb *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
AddEntry *entry = [self.fetchedResultsController objectAtIndexPath:indexPath];
[cell configureCellforTable:entry];
return cell;
}
-(NSFetchRequest *)entryListFetchRequest {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"AddEntry"];
fetchRequest.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:NO]];
return fetchRequest;
}
-(NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
NSFetchRequest *fetchRequest = [self entryListFetchRequest];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:coreDataStack.managedObjectContext sectionNameKeyPath:#"sectionName" cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;}
According to the docs, updateSearchResultsForSearchController: is "called when the search bar's text or scope has changed or when the search bar becomes first responder."
So, within this method you want to update your table to show the proper search results. This is what mine looks like (yours will look different but the idea is the same):
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
//make sure model has only results that correspond to the search
[self updateFilteredContentWithSearchText:[self.searchController.searchBar text]];
//update the table now that the model has been updated
[self.specialtySearchResultsTVC.tableView reloadData];
}
//helper method
- (void)updateFilteredContentWithSearchText:(NSString*)searchText
{
[self.specialtySearchResultsTVC.filteredSpecialties removeAllObjects];
for (Specialty *specialty in self.specialties)
{
NSRange nameRange = [specialty.name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound)
{
[self.specialtySearchResultsTVC.filteredSpecialties addObject:specialty];
}
}
}
I'm using iOS7 Xcode 5 with Parse.com's SDK. While querying data via parse, I'm trying to construct a Person (NSObject) for each returned object and create an NSArray of defaultPeople.
Here is the code for the Person:
Person.h
// Person.h
#import <Foundation/Foundation.h>
#interface Person : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) UIImage *image;
#property (nonatomic, assign) NSUInteger age;
#property (nonatomic, strong) NSString *gender;
#property (nonatomic, strong) NSString *location;
#property (nonatomic, strong) NSString *tagline;
#property (nonatomic, strong) NSString *objectId;
- (instancetype)initWithName:(NSString *)name
image:(UIImage *)image
age:(NSUInteger)age
gender:(NSString*)gender
location:(NSString*)location
tagline:(NSString*)tagline
objectId:(NSString*)objectId;
#end
Person.m:
// Person.m
#import "Person.h"
#implementation Person
#pragma mark - Object Lifecycle
- (instancetype)initWithName:(NSString *)name
image:(UIImage *)image
age:(NSUInteger)age
gender:(NSString*)gender
location:(NSString *)location
tagline:(NSString*)tagline
objectId:(NSString *)objectId {
self = [super init];
if (self) {
_name = name;
_image = image;
_age = age;
_gender = gender;
_location = location;
_tagline = tagline;
_objectId = objectId;
}
return self;
}
#end
Now here's the code I am using to try and create the array in my view controller .m file :
- (NSArray *)defaultPeople {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"Current City for Querying: %#", [defaults objectForKey:#"CurrentCity"]);
if ([defaults objectForKey:#"CurrentCity"]) {
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query whereKey:#"CurrentCity" equalTo:[defaults objectForKey:#"CurrentCity"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
NSString *userID = object.objectId;
NSString *first = [object objectForKey:#"FirstName"];
NSString *city = [object objectForKey:#"CurrentCity"];
NSUInteger age = (int)[object objectForKey:#"Age"];
NSString *gender = [object objectForKey:#"Gender"];
NSString *tagline = [object objectForKey:#"Tagline"];
Person *p = [[Person alloc]
initWithName:first
image:[UIImage imageWithData:
[NSData dataWithContentsOfURL:
[NSURL URLWithString:
[object objectForKey:#"PictureURL"]]]]
age:age
gender:gender
location:city
tagline:tagline
objectId:userID];
[self.people addObject:p]
}
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
return self.people; //people was defined in the interface as:
//#property (nonatomic, strong) NSMutableArray *people;
}
I know that the querying is fine because I've NSLogged each NSString/NSUInteger in the for loop and it always returns the right value. My problem is creating a new Person object from those values and adding it to the defaultPeople array after each iteration. The result of this code is that my defaultPeople array always returns (null). PLEASE HELP!!! Thanks :)
Clayton
Ok guys FINALLY I figured out how do do this in a block that actually works:
- (void)queryForAllPostsNearLocation:(CLLocation *)currentLocation withNearbyDistance:(CLLocationAccuracy)nearbyDistance {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:1 forKey:#"Users"];
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
// If no objects are loaded in memory, we look to the cache first to fill the table
// and then subsequently do a query against the network.
if (query.countObjects == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
// Create a PFGeoPoint using the current location (to use in our query)
PFGeoPoint *userLocation =
[PFGeoPoint geoPointWithLatitude:[Global shared].LastLocation.latitude longitude:[Global shared].LastLocation.longitude];
// Create a PFQuery asking for all wall posts 1km of the user
[query whereKey:#"CurrentCityCoordinates" nearGeoPoint:userLocation withinKilometers:10];
// Include the associated PFUser objects in the returned data
[query includeKey:#"objectId"];
//Run the query in background with completion block
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) { // The query failed
NSLog(#"Error in geo query!");
} else { // The query is successful
defaultPeople = [[NSMutableArray alloc] init];
// 1. Find new posts (those that we did not already have)
// In this array we'll store the posts returned by the query
NSMutableArray *people = [[NSMutableArray alloc] initWithCapacity:100];
// Loop through all returned PFObjects
for (PFObject *object in objects) {
// Create an object of type Person with the PFObject
Person *p = [[Person alloc] init];
NSString *userID = object.objectId;
p.objectId = userID;
NSString *first = [object objectForKey:#"FirstName"];
p.name = first;
NSString *city = [object objectForKey:#"CurrentCity"];
p.location = city;
NSString *age = [object objectForKey:#"Age"];
p.age = age;
NSString *gender = [object objectForKey:#"Gender"];
p.gender = gender;
NSString *tagline = [object objectForKey:#"Tagline"];
p.tagline = tagline;
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[object objectForKey:#"PictureURL"]]]]];
p.image = img;
if (![p.objectId isEqualToString:myID] && ![p.gender isEqualToString:myGender] && ![people containsObject:p]) {
[people addObject:p];
NSLog(#"Person: %#",p);
}
}
[defaultPeople addObjectsFromArray:people];
[[Global shared] setDefaultPeople:defaultPeople];
NSLog(#"Default People: %#",[Global shared].defaultPeople);
NSLog(#"Success. Retrieved %lu objects.", (unsigned long)[Global shared].defaultPeople.count);
if (defaultPeople.count == 0) {
[defaults setBool:0 forKey:#"Users"];
} else {
[defaults setBool:1 forKey:#"Users"];
}
}
}];
}
The BOOL returns on the bottom are to let the controller know whether or not to switch view controllers when prompted. If the switch controller toggle is hit, it only switches if the BOOL = 1, i.e. there are people in the area.
Thanks for all your help guys. Seriously.
[self.people addObject:p] is happening in the background thread so "return self.people" happens before self.people is updated. Thats why it is always returns nil.
instead of [query findObjectsInBackground] you can do
NSArray *objects = [query findObjects]
You need to return people inside the block, otherwise it will hit the return statement before it finishes finding the objects. It's finding them asynchronously with the block.
Another alternative is to get rid of the block and do:
NSArray *array = [query findObjects];
for (PFObject *object in array) {
NSString *userID = object.objectId;
NSString *first = [object objectForKey:#"FirstName"];
NSString *city = [object objectForKey:#"CurrentCity"];
NSUInteger age = (int)[object objectForKey:#"Age"];
NSString *gender = [object objectForKey:#"Gender"];
NSString *tagline = [object objectForKey:#"Tagline"];
Person *p = [[Person alloc]
initWithName:first
image:[UIImage imageWithData:
[NSData dataWithContentsOfURL:
[NSURL URLWithString:
[object objectForKey:#"PictureURL"]]]]
age:age
gender:gender
location:city
tagline:tagline
objectId:userID];
[self.people addObject:p];
}
return self.people;
I am new to IOS programming and was going thru what should be an easy to utilize and understand tutorial at the following address `http://www.youtube.com/watch?v=twQ6UjhF1Ms'
I am getting warning (**) at this section of the viewcontroller.m file
NSString *meat = Meats[MeatRow]; **unused variable"meat"
NSString *cheese = Cheeses [CheeseRow]; **unused variable"cheese"
NSString *bread = Breads [BreadRow]; **unused variable"bread"
NSString *msg = [[NSString alloc]initWithFormat:#"You ordered a %# and %# on %# Bread"]; ** More "%" conversions than data arguments
Here is the viewcontroller.h code
//
// ViewController.h
// PickerViewPart2
//
// Created by on 12/23/13.
// Copyright (c) 2013 . All rights reserved.
//
#import <UIKit/UIKit.h>
#define kMeatComponent 0
#define kCheeseComponent 1
#define kBreadComponent 2
#interface ViewController : UIViewController <UIPickerViewDataSource,UIPickerViewDelegate>
#property (nonatomic, strong)NSArray *Meats;
#property (nonatomic, strong)NSArray *Cheeses;
#property (nonatomic, strong)NSArray *Breads;
- (IBAction)makeSandich:(UIButton *)sender;
#property (weak, nonatomic) IBOutlet UILabel *sandwichLabel;
#property (weak, nonatomic) IBOutlet UIPickerView *picker;
#end
and the Viewcontroller.m code if it helps any one. I am lost or else been looking at it way to long to find what the issue is:
//
// ViewController.m
// PickerViewPart2
//
// Created by on 12/23/13.
// Copyright (c) 2013 . All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize Meats, Cheeses, Breads, picker;
- (void)viewDidLoad
{
[super viewDidLoad];
Meats = #[#"Bologna", #"Turkey", #"Ham", #"Chicken", #"Tuna", #"RoastBeef"];
Cheeses = #[#"Swiss", #"Cheddar", #"Feta", #"American", #"Pepper Jack"];
Breads = #[#"Wheat", #"White", #"Rye", #"Sour Dough", #"Pumpernickel"];
Meats = [Meats sortedArrayUsingSelector:#selector(compare:)];
Cheeses = [Cheeses sortedArrayUsingSelector:#selector(compare:)];
Breads = [Breads sortedArrayUsingSelector:#selector(compare:)];
}
-(void) didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
- (IBAction)makeSandwich:(UIButton *)sender {
NSInteger MeatRow = [picker selectedRowInComponent:kMeatComponent];
NSInteger CheeseRow = [picker selectedRowInComponent:kCheeseComponent];
NSInteger BreadRow =[picker selectedRowInComponent:kBreadComponent];
NSString *meat = Meats[MeatRow];
NSString *cheese = Cheeses [CheeseRow];
NSString *bread = Breads [BreadRow];
NSString *msg = [[NSString alloc]initWithFormat:#"You ordered a %# and %# on %# Bread"];
_sandwichLabel.text=msg;
}
#pragma mark - UIPickerCView Datasource & Delegate Methods
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 3;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (component == kMeatComponent)
return [Meats count];
else if (component == kCheeseComponent)
return [Cheeses count];
else
return [Breads count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (component == kMeatComponent)
return Meats[row];
else if (component == kCheeseComponent)
return Cheeses[row];
else return Breads[row];
}
- (IBAction)makeSandich:(UIButton *)sender {
}
#end
You are not using any of the varriable "meat,cheese,bread" try this updated code this will surely clear the warning from your code.
NSString *meat = Meats[MeatRow]; **unused variable"meat"
NSString *cheese = Cheeses [CheeseRow]; **unused variable"cheese"
NSString *bread = Breads [BreadRow]; **unused variable"bread"
NSString *msg = [[NSString alloc]initWithFormat:#"You ordered a %# and %# on %# Bread",meat,cheese,bread]; ** More "%" conversions than data arguments
I'm doing a calculator app base on a online tutorial, itunes.apple. com/itunes-u/ipad-iphone-application- development/ id473757255 (tut 2)
I followed every step closely and all was fine, until the finishing step of a method call performOperation. When I build and run, the numbers and enter function work fine. Only the operation method is not working. So I presume that the main trouble is with the operation method.
BrainCalculator.h
#interface CalculatorBrain : NSObject
-(void) pushOperand: (double)operand;
-(double) performOperation: (NSString*) operation;
#end
BrainCalculator.m
#import "CalculatorBrain.h"
#interface CalculatorBrain()
#property (nonatomic, strong) NSMutableArray* _operandStack;
#end
#implementation CalculatorBrain
#synthesize _operandStack;
-(NSMutableArray *)operandStack
{
if (!_operandStack){
_operandStack= [[NSMutableArray alloc ]init];
}
return _operandStack;
}
-(void)pushOperand:(double)operand{
NSNumber *operandObject = [NSNumber numberWithDouble:operand];
[self.operandStack addObject:operandObject];
}
-(double)popOperand{
NSNumber *operandObject= [self.operandStack lastObject];
if (operandObject) [self.operandStack removeLastObject];
return [operandObject doubleValue];
}
-(double)performOperation:(NSString *)operation
{
double result = 0;
if ([operation isEqualToString:#"+"]){
result=[self popOperand] + [self popOperand];
}else if ([#"*" isEqualToString:operation]){
result = [self popOperand] * [self popOperand];
}else if ([operation isEqualToString:#"-"]){
double subtrahend = [self popOperand];
result = [self popOperand] - subtrahend;
}else if( [operation isEqualToString:#"/"]){
double divisor = [self popOperand];
if (divisor) result = [self popOperand] / divisor;
}
[self pushOperand:result];
return result;
}
#end
Initially, it seem to me that the performOperation method was pretty fishy, so I tried fiddling the
}else if ([#"*" isEqualToString:operation]){
to
}else if ([operation isEqualToString:#"*"]){
hoping it would work, but sadly it didn't.
Just for additional information
viewcontroller.m
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController ()
#property (nonatomic) BOOL userIsInTheMiddleOfEnteringANumber;
#property (nonatomic, strong) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize display;
#synthesize userIsInTheMiddleOfEnteringANumber;
#synthesize brain= _brain;
-(CalculatorBrain*)brain
{
if(!_brain)_brain = [[CalculatorBrain alloc]init];
return _brain;
}
- (IBAction)digitPressed:(UIButton *)sender {
NSString * digit= [ sender currentTitle];
if (userIsInTheMiddleOfEnteringANumber){
self.display.text = [self.display.text stringByAppendingString:digit];
}
else{
self.display.text=digit;
self.userIsInTheMiddleOfEnteringANumber = YES;
}
}
- (IBAction)enterPressed {
[self.brain pushOperand:[self.display.text doubleValue]];
self.userIsInTheMiddleOfEnteringANumber = NO;
}
- (IBAction)operationPressed:(UIButton *)sender {
if (self.userIsInTheMiddleOfEnteringANumber){
[self enterPressed];
}
NSString *operation = [sender currentTitle];
double result = [self.brain performOperation:operation];
self.display.text = [NSString stringWithFormat:#"%g", result];
}
#end
help will be greatly appreciated as I'm practising xcode to prepare myself for my final year major project.
In the Core Data Programming Guide under "Transformable Attributes" here.
It is stated "You can now use the attribute as you would any other standard attribute, as illustrated in the following code fragment:"
The follow line of code is listed newEmployee.favoriteColor = [NSColor redColor];
I am trying to do something similar in my code but it doesn't work. Here is my code:
In Entry.h:
#interface Entry : NSManagedObject
{
}
#property (nonatomic, retain) NSAttributedString * contentString;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) NSManagedObject * journal;
#end
and in Entry.m:
#implementation Entry
#dynamic contentString;
#dynamic date;
#dynamic journal;
- (void)awakeFromInsert {
[super awakeFromInsert];
self.date = [NSDate date];
}
#end
Elsewhere I have this code:
Entry *newEntry =
[NSEntityDescription insertNewObjectForEntityForName:#"Entry"
inManagedObjectContext:[self managedObjectContext]];
newEntry.contentString = [[[NSAttributedString alloc] initWithString:#"MyString"] autorelease];
newEntry.journal = self.journal;
The line
newEntry.contentString = [[[NSAttributedString alloc] initWithString:#"MyString"] autorelease];
is equivalent to
newEmployee.favoriteColor = [NSColor redColor];
As far as I can tell however this doesn't work. I get a runtime error:
2010-10-13 09:02:08.577 JournalMaker[2437:a0f] Cannot create NSData
from object MyString{ } of class NSConcreteAttributedString
I have no idea what this error message is supposed to mean. Can someone explain?