Programmatically get a Storyboard ID? - ios

Trying to see if a UIViewController or UIView can identify its Storyboard ID. So was hoping for:
UIViewController *aViewController;
NSString *storyboardID = aViewController.storyboard.id; //not an actual property
or:
NSString *storyboardID = [aViewController.storyboard valueForKey:#"storyboardId"]; //also not a working call
But no joy and couldn't find a similar solution online. Does anyone know if this is even possible?

You can use the restorationIdentifier, it's right above the Storyboard identifier and it's a UIViewController property.

You can use the Restoration ID:
NSString *restorationId = self.restorationIdentifier;
Just check the checkbox 'Use Storyboard ID'

The storyboard id is only meant to find and instantiate a VC from a storyboard.
As written in the UIStoryboard reference:
"This identifier is not a property of the view controller object itself and is only used by the storyboard file to locate the view controller."
Why do you need it?

You can also try doing something like this:-
NSString *storyboardId = [viewController valueForKey:#"storyboardIdentifier"];
This will precisely give you the Storyboard Id that you have set via interface builder.
Swift extension:
extension UIViewController {
var storyboardId: String {
return value(forKey: "storyboardIdentifier") as? String
}
}

The most reliable method for returning the "id" of the UIViewController or UIView is...
NSString *viewControllerName = [[NSString alloc] initWithString:viewController.nibName];
This will return... "29w-Ic-LNo-view-FDu-oq-UpZ", where "29w-Ic-LNo" is the Object ID of the UIViewController and "FDu-oq-UpZ" is the Object ID of the UIView.
However, you may also use...
NSString *viewControllerName = [[NSString alloc] initWithString:viewController.title];
This will return the "Title" of the UIViewController in the Attributes Inspector; so just as easily as you added the Storyboard ID to the UIViewController, you may also add a title.

You can compare with class name .
import class and then try.
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *root = [viewControllers objectAtIndex:0];
if ([root isKindOfClass:[UserLogin class]]) {
//--- do ---
}

Related

How to make sure a name string of storyboard in an iOS project is right?

In iOS project:
I always create a UIViewController by UIStroyboard in this way.
swift:
let sb = UIStoryboard(name: "XXXlectViewController", bundle: Bundle.main)
objective -c
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"XXXlectViewController" bundle:[NSBundle mainBundle]];
Then I access a UIViewController form the storyboard.
If somebody else changes the name string accidentally. This project would not work as expected.
Sometimes, I can't make sure that the string typed by me is correct.
As you know, If I create a UIViewContrller by using pure code.
let xxxVC = xxxVC()
XXXVC *vc = [[XXXVC alloc] init];
When I Command B/R, I will get the error alert. This can help us to spot the error.
How to make sure a name string of storyboard in an iOS project is right?
How to reduce the danger of this way which uses storyboard to create UIViewControll instance?
Do you use the Unit text to check the UIViewController created by UIStoryboard?
How can I do it?
For Objective-C, you can declare your storyboard names as constants and use them in your code.
In your .h file
FOUNDATION_EXPORT NSString *const MainStoryboaardIdentifier;
In your .m file
NSString *const MainStoryboaardIdentifier = #"Main";
And for swift, the easiest can be defining an enum for them:
enum StoryboardIdentifier: String {
case Login = "Login"
case Main = "Main"
case Options = "Options"
}
and use .Main or .Login.
This way the auto-complete will also work and mistyping can be avoided. Furthermore, unit testing should also be easier. Using a specific identifier in the UIStoryboard initializer should result in the respective viewController.

Cannot access a variable of other view [duplicate]

This question already has answers here:
Accessing a swift property from objC
(2 answers)
Closed 5 years ago.
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
NSInteger userID = gesture.view.tag;
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main"
bundle:nil];
OthersProfile *vc = (OthersProfile*)[storyboard instantiateViewControllerWithIdentifier:#"othersprofile"];
NSString *strUserID = [NSString stringWithFormat:#"%ld", (long)userID];
vc.userID = strUserID;
[self.viewController.navigationController pushViewController:vc
animated:YES];
I am trying to access another view's variable and assign a value.
I declared that userID var on another view as
var userID = String()
But it says Property 'userID' not found on object of type 'OthersProfile *'?
Any idea how can i fix this?
Check the access modifiers on the var and its parent class.
this declaration
class OthersProfile:UIVIewController {
var userID = String()
}
will not always expose your inner variable. It depends on your project setup.
You can always check the contents of the "MyModule-Swift.h" synthetic header by Command-clicking it to see what has been exposed by the Swift compiler and how it has converted the Swift attributes to Objective-C
You want to get something like this
SWIFT_CLASS("_TtC5MyModule22OthersProfile")
#interface OthersProfile : UIViewController
#property (nonatomic, copy) NSString* _Nonnull userID;
The easiest way through is to start marking inaccessible things as public or open e.g
public class OthersProfile:UIVIewController {
var userID = String()
}
or
class OthersProfile:UIVIewController {
public var userID = String()
}
Later on you can back the access off if important.
I don't know nothing about objective C, but to me... probabily the problem is your cast.
Please verify what type is your VC with X-Code.. probabily is a ViewControler... and not your CustomViewControler.

access to property found with isMemberOfClass

How can I get access to a property of a ViewController when I have created an object of it like this:
for (UIViewController* vc in self.navigationController.viewControllers)
{
if ([vc isMemberOfClass:NSClassFromString(#"myViewController")])
{
// change property value on viewcontroller vc, for instance: vc.myText = #"hello" ??
}
}
thanks in advance!
You need to cast to let the compiler know the data type (or cheat and set it by an indirect method):
myViewController *mvc = (myViewController *)vc;
mvc.myText = #"hello";
Note also that class names should start with a capital first letter.
Just use simply like this:
(myViewController *)vc.myText = #"hello"
myText needs to be public variable also.

In iOS how to get object fromViewController name?

I know that this is double question. I know that I can use property in toViewController to get name of UIViewController to get NSString which tells me where I am coming from.
Anyway I want to ask if there a simple way to get name of UIViewController when unwinding from segue.
I have a UIViewController with segues to 3 forms. I programatically return to that view controller. I need to run a specific code only when I am returning from one of view controllers. My goal is using string from name of fromViewController start that specific code.
Using UIViewController by NSString from its class name isn't safe enough because the name can be changed.
You can use isKindOfClass instead:
UIViewController *destinationViewController = segue.destinationViewController;
if ([destinationViewController isKindOfClass:[MyViewControllerClass1 class]]) {
// put code related to transition to MyViewControllerClass1
}
else if ([destinationViewController isKindOfClass:[MyViewControllerClass2 class]]) {
// put code related to transition to MyViewControllerClass2
}
You can use:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
UIViewController *destinationViewController = segue.destinationViewController;
NSString * identifier = destinationViewController.identifier;
NSString * title = destinationViewController.title;
}
Create a Custom delegate method in the primary VC, create 3 strings with unique name so that u can identify.
EG.
NSString* stringFrmFORM1, *stringFrmFORM2, *stringFrmFORM3;
-(void)setString:(NSString*)myString{
//set the string from the VC1,2,3 to each string based on Primary VC's strings
}
Call the delegate method from each registration VC, and set those Strings.
You will have your registration strings to each of the Unique strings that you have set, from each of the Registration VC's.
To answer your base question, you can get the name of a class in string form with:
NSString *strClassName = NSStringFromClass([fromViewController class]);
but as #AlexPeda pointed out in ze answer, -isKindOfClass: would be better.
if ([fromViewController isKindOfClass:[SpecificViewController class]]) {
//run your 'specific' code
}

setting text of UITextField from another class

I am a beginner in "iOS", as will become clear from this question!! I am writing unit tests for my iOS app. I am trying to set the UITextField from the test class. Every time I set the username textfield text from the test case it returns null. Is there no way I can do this? I don't really want to change the code in my controller class for a test!
All the examples online create an instance of a class and set the text like below except using #synthesize (which I thought wasn't needed in "iOS7"), why is it returning null?
Code in Controller.h :
#property (nonatomic, retain) IBOutlet UITextField *username;
Test Case class :
SignUpViewController *viewController = [[SignUpViewController alloc]init];
viewController.username.text = #"username#example.com";
username.text =null
Since your property is declared using IBOutlet, I assume you're using storyboards for your views. If this is the case, then it's not an issue of the textField's text being nil, it's an issue of the whole textField being nil.
When a view controller is loaded from the storyboard, all your IBOutlets (provided they're hooked up correctly), are initialized for you. When running unit tests, there is no interaction with the storyboard, so your textField will not be initialized.
To get around this issue, you can create and assign the textField yourself:
SignUpViewController *viewController = [[SignUpViewController alloc]init];
viewController.username = [[UITextField alloc] init];
viewController.username.text = #"username#example.com";
Or, even better, you could take a look at OCMock, and create and assign a mock text field in your unit tests.
You need to load the view first.
SignUpViewController *viewController = [[SignUpViewController alloc]init];
[viewController view]; // !!
viewController.username.text = #"username#example.com";
Just because a property exists, doesn't mean the instance variable that backs it has been created. That particular UITextField is a reference to an object loaded from a NIB file (see the IBOutlet attribute),so you probably want to initialize the view controller using:
NSString *nibname = #"SignUpViewController"; // JUST GUESSING!
SignUpViewController *viewController = [[SignUpViewController alloc] initWithNibName:nibname
bundle:nil];
To get around this issue, you can create and assign the view of view controller yourself in unit tests class by writing this:
let _ = self.mockSubject.view
Here mockSubject is the viewController.

Resources