I am trying to set a variable in the UIViewController I have, but after I return to the controller in viewWillAppear it print null.
the float need to be : A calls B -> B set the string in A and return to A -> A print the string.
UIViewController A:
#property NSString *paramsAsString;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"STRING: %#", _paramsAsString); } // output 'STRING: (null)'
- (void)goToBrokersSearch {
B *destController = [[B alloc] initWithSearchParams: A.paramsAsString];
destController.delegate = view; // view is a non nil A UIViewController object
[self.navigationController pushViewController:destController animated:NO];}
UIViewController B:
#property A *delegate;
- (void)search {
_delegate.paramsAsString = params; // params - non nil NSString
[self.navigationController popViewControllerAnimated:false];}
You didn't mention the order of calling for these functions. I would suggest you use breakpoint and debug if the order of function calls is as you expecting. and the second doubt: paramsAsString should not be weak property or variable.
Related
I have a class MyOperation that has a property localizedTitle that should return a localized title but the title is being set from outside:
#interface MyOperation
- (instancetype)initWithTitle:(NSString*)title;
#property (readOnly) NSString *localizedTitle;
#end
#interface PTImageOperationSession() {
NSString* _operationTitle;
}
#implementation MyOperation
- (instancetype)initWithTitle:(NSString*)title
{
[self retainSelf];
self = [super init];
if (self)
{
_operationTitle = title;
}
return self;
}
- (NSString *)localizedTitle {
return _operationTitle;
}
#end
- (void)foo {
MyOperation *operation = [[MyOperation alloc] initWithTitle:NSLocalizedString(#"MyLocalizedTitle", nil)]; // Good.
NSSting *titleString = [self titleString]; // Can be different strings at runtime.
MyOperation *operation1 = [[MyOperation alloc] initWithTitle: titleString]; // Bad because the title is not localized.
}
Question: Is it possible to insure that the class will always be initialised with localised title? My responsibility as a class owner is to return a localized title, but it is being set from outside so I have no control on it. Would you tag it as a "design issue"?
Passing variable to NSLocalizedString macro shouldn't be any problem, here is what I did for testing purpose:
Localizable.strings
"MyString"="My sample localized string";
And my TestClass
#interface TestClass : NSObject
#property (readonly) NSString *localizedTitle;
-(instancetype)initWithTitle:(NSString *)title;
#end
#implementation TestClass {
NSString *_title;
}
-(instancetype)initWithTitle:(NSString *)title {
self = [super init];
if (self) {
_title = NSLocalizedString(title, nil);
}
return self;
}
-(NSString *)localizedTitle {
return _title;
}
#end
Init my test class, then access its property
TestClass *myClass = [[TestClass alloc] initWithTitle:#"MyString"];
NSLog(#"%#", myClass.localizedTitle);
This is what I have in console:
2018-11-05 19:16:36.268393 TestApp[1471:352553] My sample localized string
Update
The macro:
#define NSLocalizedString(key, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:#"" table:nil]
Is the shortcut to localizedStringForKey:value:table: function & according to the document:
Return Value
A localized version of the string designated by key in
table tableName. This method returns the following when key is nil or
not found in table:
If key is nil and value is nil, returns an empty string.
If key is nil and value is non-nil, returns value.
If key is not found and value is nil or an empty string, returns key.
If key is not found and value is non-nil and not empty, return value.
If you pass a non-existence key to the macro, you will receive the key itself. That's the designated behavior.
By the way, in common sense, you can't ask for a localized string if it isn't defined, right?
I have a NSString property, self.textFromTextVC, in a Viewcontroller and it's value becomes null in the IBAction method.
- (IBAction)buttonPressed:(id)sender
{
NSLog(#"text before alarm is created: %#", self.textFromTextVC);
}
The methods below are in the same '.m' file and they keep the value of the NSString property.
-(void)setPropertyTextToReceivedText:(NSString *)text
{
self.textFromTextVC = text;
NSLog(#"text received from text VC: %#", self.textFromTextVC);
[self doesStringKeepValue]; //I call this method to check and see if the NSString value
//was retained
}
-(void)doesStringKeepValue
{
NSLog(#"keep value: %#", self.textFromTextVC); //NSString value the same from the above
//method
}
Below is how I have declared the NSString property:
#property (nonatomic, copy) NSString *textFromTextVC;
Basically, I'm setting the self.textFromTextVC before the IBAction method is called and that is why I'm confused. I'm really not sure what is going on. I have ARC selected.
I'm hoping that I'm just making a simple mistake...help?
Thanks,
Below is the method in another viewcontroller where I called setPropertyTextToReceivedText:
#implementation TextViewController
#synthesize typedText;
- (IBAction)doneButton:(id)sender {
[self.typedText resignFirstResponder];
AlarmViewController *receiver = [[AlarmViewController alloc]init];
[receiver setPropertyTextToReceivedText:self.typedText.text];
//[self showAlert];
}
What your problem is receiver is different object than your VC which is shown (present/pushed).
AlarmViewController *receiver = [[AlarmViewController alloc]init];
[receiver setPropertyTextToReceivedText:self.typedText.text];
Change this:
NSLog(#"text before alarm is created: %#", self.textFromTextVC);
To this:
NSLog(#"%#: text before alarm is created: %#", self, self.textFromTextVC);
And it will probably show you that you are indeed looking at two different object instances of the same class.
I think you forgot:
#synthesize textFromTextVC;
I created a simple UIViewController with a custom init method like this:
-(id)initWithGroupNumber:(NSString *)groupNumber {
if ((self = [super init]) == nil) {
return nil;
}
self.levelGroup = groupNumber;
return self; }
levelGroup is a property written in the .h file
#property (nonatomic, retain) NSString *levelGroup;
When I call the method above this way:
LevelsViewController *lvc = [[LevelsViewController alloc]initWithGroupNumber:#"5"];
the controller is allocated but all the property inside are set to nil. I can't understand why.
First of all when you deal with classes that have subclass of type mutable (e.g. NSMutableString), use copy.
So, your property should become:
#property (nonatomic, copy) NSString *levelGroup;
Then, inside the UIViewController synthesize the property
#synthesize levelGroup;
and in init do the following:
-(id)initWithGroupNumber:(NSString *)groupNumber {
if (self = [super init]) {
levelGroup = [groupNumber copy];
}
return self;
}
As written in the memory management guide you should not use self. inside init and in dealloc.
Use your property self.levelGroup to get or set the value.
Remember to release in dealloc:
[levelGroup release];
Hope it helps.
Replace your
self.levelGroup = [[NSString alloc]init];
with
self.levelGroup = groupNumber; // actually uses your init value.
I am trying to set the value of an NSTextField, but it's not working properly.
I have a button linked to an IBAction, and when I set it using self, it works fine:
#import <Foundation/Foundation.h>
#interface TestMessage : NSObject {
IBOutlet NSTextField *text;
}
- (IBAction) setMessage: (id) controller;
- (void) Message:(NSString *) myMessage;
#end
#import "TestMessage.h"
#implementation TestMessage
- (IBAction) setMessage: (id) controller {
// This works
[self Message:#"Hello"];
// but this doesn't
TestMessage * messageTest= [TestMessage new];
[messageTest Message:#"Hi"];
}
- (void) Message: (NSString *) myMessage {
[text setStringValue: myMessage];
NSLog(#"Message Was Called");
// This returns <NSTextField: 0x1001355b0> when called
// using self, but null when called the other way.
NSLog(#"%#", text);
}
#end
I've searched for a while, but still can't find the answer.
I guess it has something to do with the delegate, but I'm not sure.
Thanks in advance.
Are you sure message is called when you call it from anotherFuntion? If anotherFuntion is a method of another class, calling [self message:] won't work as you expected to...
I know this is an old post, but I have been fiddling with the same issue today.
You have to return string value in textfield:
[textField stringValue];
The code
TestMessage * messageTest = [TestMessage new];
is unusual, specifically new. I'm going to assume that new is just a class method does normal alloc/init equivalent to
TestMessage * messageTest = [[TestMessage alloc] init];
The main problem is that IBOutlet NSTextField *text will be initialized only if the class TestMessage is loaded with a Nib file. It would have to be named as the class of an object in Interface Builder, like so
and you would have to implement initWithCoder and encodeWithCoder something like this in order to extract your field value from the IB encoding:
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
self.text = [coder decodeObjectForKey:#"text"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
[super encodeWithCoder:coder];
[coder encodeObject:self.text forKey:#"text"];
}
Fundamentally, IBOutlet fields do not get wired up wherever you create an instance of that class. If they did, how would you express that field A should be wired to UI object A and field B should be wired to UI object B? The connection is established only in the context of loading a class from a Nib file.
I'm new to objective-c and I'm finding that I don't know how to correctly assert that a text property on some given label is equal to a raw string value. I'm not sure if I just need to cast the label as NSString or if I need to modify my assert statement directly.
#interface MoreTest : SenTestCase {
MagiczzTestingViewController* controller;
}
- (void) testObj;
#end
#implementation MoreTest
- (void) setUp
{
controller = [[MagiczzTestingViewController alloc] init];
}
- (void) tearDown
{
[controller release];
}
- (void) testObj
{
controller.doMagic;
STAssertEquals(#"hehe", controller.label.text, #"should be hehe, was %d instead", valtxt);
}
#end
The implementation of my doMagic method is below
#interface MagiczzTestingViewController : UIViewController {
IBOutlet UILabel *label;
}
#property (nonatomic, retain) UILabel *label;
- (void) doMagic;
#end
#implementation MagiczzTestingViewController
#synthesize label;
- (void) doMagic
{
label.text = #"hehe";
}
- (void)dealloc {
[label release];
[super dealloc];
}
#end
The build is fine when I modify the assert to compare a raw NSString to another but when I try to capture the text value (assuming it's of type NSString) it fails. Any help would be much appreciated!
STAssertEquals() checks for identity of the two values provided, so it's equivalent to doing this:
STAssertTrue(#"hehe" == controller.label.text, ...);
Instead, you want STAssertEqualObjects(), which will actually run an isEqual: check like the following:
STAssertTrue([#"hehe" isEqual:controller.label.text], ...);
You need to load the nib of the view controller. Otherwise there won't be any objects for the label outlet to be hooked up to.
One way to do this is to add an ivar for the view controller's view to your test case:
#interface MoreTest : SenTestCase {
MagiczzTestingViewController *controller;
UIView *view;
}
#end
#implementation MoreTest
- (void)setUp
{
[super setUp];
controller = [[MagiczzTestingViewController alloc] init];
view = controller.view; // owned by controller
}
- (void)tearDown
{
view = nil; // owned by controller
[controller release];
[super tearDown];
}
- (void)testViewExists
{
STAssertNotNil(view,
#"The view controller should have an associated view.");
}
- (void)testObj
{
[controller doMagic];
STAssertEqualObjects(#"hehe", controller.label.text,
#"The label should contain the appropriate text after magic.");
}
#end
Note that you also need to invoke super's -setUp and -tearDown methods appropriately from within yours.
Finally, do not use dot syntax for method invocation, it is not a generic replacement for bracket syntax in message expressions. Use dot syntax only for getting and setting object state.