I have class ABCD.m, as below
**ABCD.m**
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) NSString *string;
- (void) firstMethod;
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2;
-(void) firstMethod {
// Alloc init button
self.button.enabled = NO;
}
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2 {
self.button.enabled = var1;
self.string = var2;
}
There is another class Test.m(subclass of XCTestCase) to write the unit test cases for ABCD.m
**Test.m** //Sub-class of XCTestCase
//Extension
#interface ABCD.m ()
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) NSString *string;
- (void) firstMethod;
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2;
#end
#interace Test : XCTestCase
- (void)testSomeMethod {
ABCD *abcd = [ABCD alloc] init];
BOOL *var1 = YES;
NSString *var2 = #"StackOverFlow";
[abcd firstMethod];
[abcd setTheButtonWithBool:var1 withString:var2];
nslog(#"Result1 :%hhd", self.abcd.button.isEnabled); -----
nslog(#"Result2: %#", self.abcd.string); -----
// Assert statement
}
OUTPUT:
Result 1: NO
Result 2: StackOverFlow
When i set the property 'string' it is getting set to 'StackOverFlow'. But for UIButton property 'button' it is not getting set to 'NO'.
Why cant I set 'enabled' property of UIButton where as i can set the NSString of ABCD.m from the Test.m class
The problem is simple. You never set the button property on your ABCD instance. There is no code that creates a UIButton and assigns it to the button property.
A call like self.button.enabled = NO is translated to [[self button] setEnabled:NO]. Since you haven't set button, the call to [self button] returns nil. So now you call setEnabled: on a nil object which is basically a no-op.
Add code to create a button and set the button property and the rest of the code will work properly.
Related
How to set the current value of UITextField to a property(through a custom setter) declared in category which extends UITextField class when firing editingDidBegin control event of UITextField?
You should be able to do this using a category by taking advantage of Associative References.
From the docs:
Using associative references, you can add storage to an object without
modifying the class declaration.
Here's an example that will get you going in the right direction:
.h file:
#interface UITextField (StoredProperty)
#property (nonatomic, strong) NSString *testString;
#end
.m file:
#import <objc/runtime.h>
static void *MyStoredPropertyKey = &MyStoredPropertyKey;
#implementation UITextField (StoredProperty)
- (NSString *)testString {
return objc_getAssociatedObject(self, MyStoredPropertyKey);
}
- (void)setTestString:(NSString *)testString {
objc_setAssociatedObject(self, MyStoredPropertyKey, testString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
Example use:
NSObject *obj = [NSObject new];
obj.testString = #"This is my test string";
NSLog(#"%#", obj.testString);
I have the class LearnfestItem.h :
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface LearnfestItem : NSObject
#property (strong, nonatomic) NSString * itemId;
#property (strong, nonatomic) NSString * itemTitle;
#property (strong, nonatomic) NSString * itemDescription;
#property (strong, nonatomic) NSString * itemContent;
#property (strong, nonatomic) NSString * itemType;
#property (strong, nonatomic) UIImage * itemImage;
#property (strong, nonatomic) NSDate * itemRegistered;
-(id)initWithData:(NSDictionary *)data andImage:(UIImage *)image;
#end
& Object.m :
#import "LearnfestItem.h"
#import "Defaults.h"
#implementation LearnfestItem
-(id)init
{
self = [self initWithData:nil andImage:nil];
return self;
}
-(id)initWithData:(NSDictionary *)data andImage:(UIImage *)image
{
self = [super init];
self.itemId = data[ITEM_ID];
self.itemTitle = data[ITEM_TITLE];
self.itemDescription = data[ITEM_DESCRIPTION];
self.itemContent = data[ITEM_CONTENT];
self.itemType = data[ITEM_TYPE];
self.itemImage = image;
self.itemRegistered = data[ITEM_REGISTERED];
return self;
}
#end
In my UIViewController I have a UITableView that creates a NSMutableArray of LearnfestItems within the cellForRowAtIndexPath method:
LearnfestItem * createLearnfestItem = [[LearnfestItem alloc] initWithData:learnfestItemDictionary andImage:learnfestItemImage];
NSLog(#"Insert learnfest item with id: %# at index %li", createLearnfestItem.itemId, (long)row);
[self.learnfestItemObjects insertObject:createLearnfestItem atIndex:row];
On didSelectRowAtIndexPath I want to receive the LearnfestItem from the NSMutableArray I do this by calling:
self.selectedLearnfestItem = [self.learnfestItemObjects objectAtIndex:indexPath.row];
Then I want to send it to another view controller to present the data I do this in the prepareForSegue segement:
LearnfestItemViewController * learnfestVC = [segue destinationViewController];
NSLog(#"Sending learnfest item with id: %#", self.selectedLearnfestItem.itemId);
learnfestVC.item = self.selectedLearnfestItem;
When I try to access my LearnfestItem's properties within cellForRowAtIndexPath. All I get is null... and so forth in my other table view delegate methods.. Can anyone spot what i'm doing wrong? Thanks
Code you show is missing all error and validity checking. When using NSAssert() and item.length/item.count checks, you will know what's going on.
However, based on your code I'd suggest two things:
All objects which also have mutable version should use "copy" properties. Now you have "strong" pointer to data received via init method, but if you reset the originally given data variable to point elsewhere (e.g. reusing one data variable inside for loop to init multiple items), then... I don't know what your LearnfestItem item properties will point to.
Make sure your LearnfestItemViewController *item is a copy, too.
My guess is that everything is initialised correctly, but the data disappears afterwards.
For example:
#property (nonatomic, copy) NSString * itemId; // Safe
#property (nonatomic, strong) NSString * itemId; // Not safe
When your property class has mutable variations (e.g. NSString vs. NSMutableString vs. MyMutableString), copy is safer. Using strong will create a pointer to original data, which could have been a mutable instance and could be modified afterwards. Using strong will always point to original data, even after it has been changed.
Second part:
learnfestVC.item = self.selectedLearnfestItem;
Your LearnfestItemViewController contains some property related to LearnfestItem class. Make sure it's a copy, too. When using segues, the calling object quite often just disappears. Make sure your new controller has local copy of all needed data (or use a protocol delegate, but that's a longer discussion)
Adding error and data validity checking will make your task a lot easier. Instead of trying to figure out afterwards why something doesn't work, you'll get notifications when something isn't as you're expecting.
Here's quick and dirty "maintenance" for your code. What you should get out of this is some ideas what to check, where and how. In normal situations this is overkill, but now you have a mysterious problem and need to find it. It can be hard and monotonous work.
#import Foundation;
#import UIKit;
#interface LearnfestItem : NSObject
#property (copy, nonatomic) NSString *itemId;
#property (copy, nonatomic) NSString *itemTitle;
#property (copy, nonatomic) NSString *itemDescription;
#property (copy, nonatomic) NSString *itemContent;
#property (copy, nonatomic) NSString *itemType;
#property (strong, nonatomic) UIImage *itemImage;
#property (strong, nonatomic) NSDate *itemRegistered;
- (instancetype)initWithData:(NSDictionary *)data andImage:(UIImage *)image;
#end
Object.m :
#import "Defaults.h"
#import "LearnfestItem.h"
#implementation LearnfestItem
- (instancetype)init
{
self = [self initWithData:nil andImage:nil];
return self;
}
- (instancetype)initWithData:(NSDictionary *)data andImage:(UIImage *)image
{
NSAssert(data.length, #"My Assert: missing data");
NSAssert(image, #"My Assert: missing image");
if ((self = [super init]))
{
// TODO: nil ok, if doesn't exist?
_itemId = data[ITEM_ID];
_itemTitle = data[ITEM_TITLE];
_itemDescription = data[ITEM_DESCRIPTION];
_itemContent = data[ITEM_CONTENT];
_itemType = data[ITEM_TYPE];
_itemImage = image;
_itemRegistered = data[ITEM_REGISTERED];
}
return self;
}
#end
"(original text) In my UIViewController I have a UITableView that creates a NSMutableArray of LearnfestItems within the cellForRowAtIndexPath method:"
NSAssert(learnfestItemDictionary.count, #"My Assert: missing dict");
NSAssert(learnfestItemImage, #"My Assert: missing image");
LearnfestItem *createLearnfestItem = [[LearnfestItem alloc] initWithData:learnfestItemDictionary andImage:learnfestItemImage];
NSLog(#"Insert learnfest item with id: %# at index %#", createLearnfestItem.itemId, #(row));
NSAssert(createLearnfestItem, #"My Assert: missing item");
NSAssert(self.learnfestItemObjects.count > row, #"My Assert: learnfestItemObjects");
self.learnfestItemObjects[row] = createLearnfestItem;
"(original text) On didSelectRowAtIndexPath I want to receive the LearnfestItem from the NSMutableArray I do this by calling:"
NSAssert(self.learnfestItemObjects.count > indexPath.row, #"My Assert: learnfestItemObjects");
self.selectedLearnfestItem = self.learnfestItemObjects[indexPath.row];
"(original text) Then I want to send it to another view controller to present the data I do this in the prepareForSegue segment:"
LearnfestItemViewController *learnfestVC = (LearnfestItemViewController *)[segue destinationViewController];
NSLog(#"Sending learnfest item with id: %#", self.selectedLearnfestItem.itemId);
learnfestVC.item = self.selectedLearnfestItem;
In my main view controller, I have a UITextField, and I am trying to save the text input into it to a NSString in my Homework model(class).
Homework.h
#import <Foundation/Foundation.h>
#interface Homework : NSObject
#property (nonatomic, strong) NSString *className;
#property (nonatomic, strong) NSString *assignmentTitle;
#end
Homework.m
#import "Homework.h"
#implementation Homework
#synthesize className = _className;
#synthesize assignmentTitle = _assignmentTitle;
#end
In my assignmentViewController, I create an object of type Homework and try to set it equal to whatever is entered into the the UITextField when the Save Button is pressed.
Assignment View Controller
#import <UIKit/UIKit.h>
#import "Homework.h"
#interface Assignment : UIViewController {
}
#property(nonatomic) IBOutlet UITextField *ClassNameField;
#property(nonatomic) IBOutlet UILabel *ClassNameLabel;
#property (weak, nonatomic) IBOutlet UIButton *SaveButton;
#property (nonatomic, strong) Homework *homeworkAssignment;
- (IBAction)Save:(UIButton *)sender;
#end
AssignmentViewController.m
- (IBAction)Save:(UIButton *)sender {
self.homeworkAssignment.className = self.ClassNameField.text;
NSLog(#"SaveButtonPressed %#", self.homeworkAssignment.className);
}
The NSLog prints out that className is (null). Can anyone help me figure out what I am doing wrong? This is my first ever iOS app (besides Hello World).
Edit: This is using ARC
Edit: I tried changing
self.homeworkAssignment.className = self.ClassNameField.text; to
self.homeworkAssignment.className = #"TEST";
and the log still shows (Null).
Double check you properly linked ClassNameField outlet and that you're initializing homeworkAssignment. Something like.-
self.homeworkAssignment = [[Homework alloc] init];
By the way, you should consider using camelCase notation for your variable names :)
Well to be honest the first steps are always hard but you should learn it the right way, héhé
First of all synthesize this way:
#synthesize labelAssignmentTitle,labelClassName;
or
#synthesize labelAssignmentTitle;
#synthesize labelClassName;
there is no need to do the following:
#synthesize className = _className;
#synthesize assignmentTitle = _assignmentTitle;
Now if you initialize the right way from the the start you'll find it a lot easier later!
HomeWork.h
#interface HomeWork : NSObject
#property (nonatomic, strong) NSString *className;
#property (nonatomic, strong) NSString *assignmentTitle;
-(id)initWithClassName:(NSString *)newClassName andAssignmentTitle:(NSString*)newAssigmentTitle;
HomeWork.m
#implementation HomeWork
#synthesize assignmentTitle,className;
-(id)initWithClassName:(NSString *)newClassName andAssignmentTitle:(NSString*)newAssigmentTitle {
self = [super init];
if(self){
assignmentTitle = newAssigmentTitle;
className = newClass;
}
return self;
}
#end
ViewController.m
- (IBAction)saveIt:(id)sender {
HomeWork *newHomeWork = [[HomeWork alloc]initWithClassName:[labelClassName text]andAssignmentTitle:[labelAssignmentTitle text]];
}
Because of this, you directly make a newHomeWork object with the parameters given by your two UITextFields.
Now print it out in your logmessage and see what happends ;)
Okay, I know there is a ton of these questions out there, because I've looked and tried some of the solutions. However, many of the ones I tried didn't work or the answer was too over my head for me to really grasp well - I'm a new developer and this is my first app. I learn by learning what not to do at this point.
I have the 'unrecognized selector sent to instance error' on a UIStepper stepperValueChanged setup. Here is the contents of the error message as it is given to me:
[DetailViewController stepperValueChanged]: unrecognized selector sent to instance 0x8637630
I will probably be ripped apart for this, but I can't really understand what's going on here - my only guess so far is to assume it has something to do with the only point in my code where stepperValueChanged exists - under the DetailViewController.h, as placed below:
#interface DetailViewController : UIViewController <UISplitViewControllerDelegate>
{
// Create GUI parameters for text fields, text labels, and the stepper:
IBOutlet UITextField *value1;
IBOutlet UITextField *value2;
IBOutlet UITextField *value3;
IBOutlet UISwitch *double_precision;
IBOutlet UILabel *value1_type;
IBOutlet UILabel *value2_type;
IBOutlet UILabel *value3_type;
IBOutlet UILabel *deriv_units;
IBOutlet UILabel *units;
IBOutlet UILabel *result;
IBOutlet UIStepper *stepper;
}
// Define properties of the above GUI parameters:
#property (nonatomic, retain) UITextField *value1;
#property (nonatomic, retain) UITextField *value2;
#property (nonatomic, retain) UITextField *value3;
#property (nonatomic, retain) UILabel *value1_type;
#property (nonatomic, retain) UILabel *value2_type;
#property (nonatomic, retain) UILabel *value3_type;
#property (nonatomic, retain) UILabel *deriv_units;
#property (nonatomic, retain) UILabel *units;
#property (nonatomic, retain) UILabel *result;
// Setup property as instance of UIStepper:
#property (nonatomic, strong) IBOutlet UIStepper *stepper;
// Setup NSString instance for segue linking:
#property (nonatomic, strong) NSString *equationName;
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
// IBActions for the Calculate button and UIStepper instance:
- (IBAction)Calculate:(id)sender;
- (IBAction)stepperValueChanged:(id)sender;
- (IBAction)double_precision:(id)sender;
#end
Any ideas what is going on here? I don't have much of a clue, and if anyone can help explain to me what exactly is in play here while addressing it, I would be more than grateful.
If you need the contents of the implementation file, let me know; I'll edit it in.
Relevant areas of the .m file:
#interface DetailViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
- (void)configureView;
#end
#implementation DetailViewController
// Synthesize an instance of NSString for segue linking:
#synthesize equationName = _equationName;;
// Synthesize all other variables:
#synthesize value1 = _value1;
#synthesize value2 = _value2;
#synthesize value3 = _value3;
#synthesize value1_type = _value1_type;
#synthesize value2_type = _value2_type;
#synthesize value3_type = _value3_type;
#synthesize deriv_units = _deriv_units;
#synthesize result = _result;
#synthesize units = _units;
#synthesize stepper = _stepper;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
self.title = _equationName;
self.stepper.stepValue = 1;
self.stepper.autorepeat = NO;
self.stepper.continuous = YES;
self.stepper.wraps = YES;
int eqNum;
if ((_equationName = #"Energy-Frequency Relation"))
{
eqNum = 1;
self.stepper.minimumValue = 1;
self.stepper.maximumValue = 3;
}
else if ((_equationName = #"Energy-Frequency-Wavelength Relation"))
{
eqNum = 2;
self.stepper.minimumValue = 1;
self.stepper.maximumValue = 4;
}
// Take _equationName quantization and use it in a switch case to determine the formula that IBAction will use:
if (dflt)
{
switch (eqNum)
{
case 1:
if ((stepper.value = 1))
{
// Change deriv_units appropriately:
self.deriv_units.text = #"Energy (Joules)";
// This is a Planck's constant calculation, we hide the second variable as the constant
// is stored:
self.value2.hidden = YES;
self.value2_type.hidden = YES;
self.value3.hidden = YES;
self.value3_type.hidden = YES;
// Now we set up the parameters of the first entry variable:
self.value1_type.text = #"Frequency (in Hz)";
double frequency = [value1.text doubleValue];
double Planck = 6.626069e-34;
double energy = Planck * frequency;
// Now we set up the return field to return results:
NSString* resultIntermediate = [NSString stringWithFormat:#"%f", energy];
self.units.text = #"J";
}
// Identical function statements under ViewDidLoad truncated
}
bool dflt;
-(IBAction)KeyboardGoAway:(id)sender
{
[self.value1 resignFirstResponder];
[self.value1 resignFirstResponder];
[self.value1 resignFirstResponder];
}
-(IBAction)double_precision:(id)sender
{
// Sets double-float 'truth' value depending on state of UISwitch:
if (double_precision.on)
{
dflt = TRUE;
}
else
{
dflt = FALSE;
}
}
#pragma mark - Calculation runtime
-(IBAction)Calculate:(id)sender
{
// Assigns numerical information to _equationName data -
// switch case can only handle integer literals
// Also handles stepper incrementation and UILabel/UITextView hiding
NSString* resultIntermediate;
self.result.text = resultIntermediate;
}
The trailing colon makes the difference. Your action method is stepperValueChanged:,
but from the error message it seems that you connected the stepper to stepperValueChanged.
There are two reason for these kind of issues.
Probable case 1:
You first declared the function like - (IBAction)stepperValueChanged;
Connected the IBAction to stepper
Changed the method to - (IBAction)stepperValueChanged:(id)sender;
Solution:
Delete old connection in the interface builder and connect it again.
Probable case 2:
In your code you are calling the method using a selector where you written like: #selector(stepperValueChanged)
Solution:
Change the selector like: #selector(stepperValueChanged:)
Usually this means you are missing the method in your .m or you might of misspelled stepperValueChanged.
Edit: Actually, I believe it needs to be stepperValueChanged: with a semicolon.
I'm making elevator thing. I'm having trouble sending data with different views using presentModalViewController. I got red message "favoriteColorString" property not found. I copied exactly the same but different form names and buttons. The "favoriteColorString" appears an error and unable to send elevator2 data.
I tried two different thing.
Elevator2View.favoriteColorString = [[NSString alloc] initWithFormat:#"Your favorite color is %#", favoriteColorTextField.text];
And
favoriteColorString = [[NSString alloc] initWithFormat:#"Your favorite color is %#", favoriteColorTextField.text];
Here's my code:
ElevatorView.h
#import <UIKit/UIKit.h>
#import "Elevator2View.h"
#interface ElevatorView : UIViewController<PassSecondColor>
{
Elevator2View *Elevator2View;
IBOutlet UITextField *favoriteColorTextField;
IBOutlet UILabel *favoriteColorLabel;
IBOutlet UILabel *secondFavoriteColorLabel;
NSString *secondFavoriteColorString;
}
#property (nonatomic, retain) Elevator2View *Elevator2View;
#property (nonatomic, retain) IBOutlet UITextField *favoriteColorTextField;
#property (nonatomic, retain) IBOutlet UILabel *favoriteColorLabel;
#property (nonatomic, retain) IBOutlet UILabel *secondFavoriteColorLabel;
#property (copy) NSString *secondFavoriteColorString;
#end
ElevatorView.m
#import "ElevatorView.h"
#import "Elevator2View.h"
#implementation ElevatorView
#synthesize Elevator2View, favoriteColorTextField, favoriteColorLabel, secondFavoriteColorLabel;
#synthesize secondFavoriteColorString;
-(IBAction)level1:(id)sender;{
favoriteColorTextField.text = #"1";
Elevator2View.favoriteColorString = [[NSString alloc] initWithFormat:#"Your favorite color is %#", favoriteColorTextField.text];
[self presentModalViewController:[[[Elevator2View alloc] init]
autorelease] animated:NO];
}
Elevator2View.h
#import <UIKit/UIKit.h>
#protocol PassSecondColor <NSObject>
#required
- (void) setSecondFavoriteColor:(NSString *)secondFavoriteColor;
#end
#interface Elevator2View : UIViewController{
IBOutlet UITextField *secondFavoriteColorTextField;
IBOutlet UILabel *favoriteColorLabel;
IBOutlet UILabel *secondFavoriteColorLabel;
NSString *favoriteColorString;
id <PassSecondColor> delegate;
}
#property (copy) NSString *favoriteColorString;
#property (nonatomic, retain) IBOutlet UITextField *secondFavoriteColorTextField;
#property (nonatomic, retain) IBOutlet UILabel *favoriteColorLabel;
#property (nonatomic, retain) IBOutlet UILabel *secondFavoriteColorLabel;
#property (retain) id delegate;
#end
Elevator2View.m
#import "Elevator2View.h"
#interface Elevator2View ()
#end
#implementation Elevator2View
#synthesize secondFavoriteColorTextField, favoriteColorLabel, secondFavoriteColorLabel;
#synthesize favoriteColorString;
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void) viewWillAppear:(BOOL)animated
{
favoriteColorLabel.text = favoriteColorString;
}
- (void) viewWillDisappear:(BOOL) animated
{
// [[self delegate] setSecondFavoriteColor:secondFavoriteColorTextField.text];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
favoriteColorLabel.text = favoriteColorString;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
See http://www.theappcodeblog.com/?p=90
The reason for your "property not found" is that you named your ivar same as class.
Dot notation is just a syntactic sugar: object.property = value is equivalent to [object setProperty:value]. In Objective C classes are also objects, and when you call Elevator2View.favoriteColorString = whatever, Xcode apparently thinks that you are attempting to call class method setFavoriteColorString of class Elevator2View.
Getting rid of this error is easy: just rename your ivar Elevator2View *Elevator2View to something else. In fact, Xcode 4.4 and newer autosynthesizes ivars for your properties: if you have a property propertyName, then Xcode will autosynthesize ivar _propertyName. Your property Elevator2View will have _Elevator2View ivar. So unless you really really need to have ivars with different naming scheme, you can get rid of your #synthesize, and you also don't need to declare ivars for you properties.
(Though I prefer to declare ivars for properties (following Xcode naming scheme), because far too often lldb doesn't show autosynthesized-without-declaring ivars in object inspector.)
That was about properties, ivars and naming conventions. But what are you doing in this code?
-(IBAction)level1:(id)sender;{
favoriteColorTextField.text = #"1";
Elevator2View.favoriteColorString = [[NSString alloc] initWithFormat:#"Your favorite color is %#", favoriteColorTextField.text];
[self presentModalViewController:[[[Elevator2View alloc] init]
autorelease] animated:NO];
}
You set value of Elevator2View's - your instance variable's - property, then create brand new object of Elevator2View class and present that as modal view controller. (By the way, presentModalViewController:animated: is deprecated in iOS 6.0). Of course, this brand new Elevator2View object has no idea what Elevator2View's (your instance variable's) properties are!