Coding a custom navigationItem.rightBarButtonItem once and having it reused in both UITableViewControllers and UIViewControllers? - uiviewcontroller

I have successfully added a rightBarButtonItem to my navigationBar, but I would prefer to only have the code to do so show up once rather than once per type of ViewController. Here's my current setup:
-->TVC
|
NVC--->TVC--->TVC--->VC
So far I've subclassed UITableViewController and moved my code for adding the button into my subclass. All 3 of my TableViewControllers are set to that subclass and it works perfectly.
However now I need my lone ViewController to also show the button, but I don't know how to accomplish this without duplicating the code from my TVC subclass. Is subclassing the right answer or do I need a different approach?
Edits:
#CarlVeazey - Sure, I call it from the viewDidLoad function.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"BETA" style:UIBarButtonItemStylePlain target:self action:#selector(betaPressed)];

Do a pull-up refactor into a UIViewController category. If your project already has one, just add this code there, otherwise press cmd-N in Xcode to create a new file and choose "Objective-C Category" and enter UIViewController in the "Category On" field.
In the interface add this method declaration:
- (void)onfConfigureRightNavigationBarButton;
And in the implementation add this method implementation:
- (void)onfConfigureRightNavigationBarButton
{
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"BETA"
style:UIBarButtonItemStylePlain
target:self
action:#selector(betaPressed)];
}
Then in any UIViewController subclass you can import your category header and call this method. You may also wish to add to your category an empty implementation of betaPressed:.
BTW, ONF is the prefix I use for non-work coding so use whatever prefix already is in your project, or none at all if you're not concerned with category name collisions.

Related

How to use contents = to add to a Scala Panel?

Sorry this must be a very silly question.. but everywhere I've been seeing Scala code examples where you just do
contents+= on a BoxPanel or some layout Panel. I figured because they have contents as mutable.buffer so you can just add and remove components.
But how do you add a component to Scala Panel? It accepts a seq so do you have to give it a list or something? I know you can just call peer.add but I want to see how Scala code does it. :)
For example contents = new Button {} isn't working.
Sorry for this simple question I'm very new to Scala..
EDIT:
Thanks for the replies. My question now though becomes.. can you ever just have a class extending Panel? Would you be able to set contents for it at all? Or is it never done and everyone always just uses the Panels associated with a layout manager?
The Panel class itself is abstract, meaning it can't be instantiated directly, and is intended as a "base" for concrete implementations of panels.
It doesn't seem to have a "common" method for adding components probably because each subclass implements its own, sometimes mutually incompatible custom one:
BoxPanel, as you've noted, has a settable Buffer,
FlowPanel seems to mandate adding components as constructor arguments,
GridBagLayout and some others implement addition via the layout Map,
etc.
As you might see from the above examples, it would be hard to specify what a general "add" method would mean in all of those cases.
EDIT in response: of course you can, there's nothing stopping you from subclassing a Panel yourself and override the contents method, e.g.:
val myPanel = new Panel() {
private val myContents = (new Content += new Button())
override def contents = myContents
}
You can also use Panel as a type parameter for your methods that process panels in a general way, etc. It's just that you can't have an instance that's just a Panel, because, again, the class is abstract, so you can't instantiate it.
Note that this is not unique to Scala, if JPanel was abstract in Java (like Component is) the outcome would be the same.
I want to see how Scala code does it.
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Container.scala#L35
I, too, practiced on some Swing code when I first learned some Scala.
Here is a Panel component that renders itself as a simple game grid:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/LightBox.scala#L286
To see how the Scala and Swing pieces fit together, see SuperMixin:
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Component.scala#L51
Assembly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L18
This is what you asked about directly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L45
If you have a button:
val button=new Button{
text="Click me!"
}
or
val label=new Label{
text="Look, i'm a label!"
}
or
object myField extends TextField{ columns=2 }
then you just use:
contents=new BoxPanel(Orientation.Vertical){
contents+=button
border=Swing.EmptyBorder(10,20,10,20)
}
or in a more simpler form:
contents=new FlowPanel(){
contents+=new Label("This is my button:")
contents+=new Button("Click me!")
border=Swing.EmptyBorder(10,20,10,20)
}

how to make UIViewController Title show up on titleView in UINavigationController?

I thought, and I may be wrong, without doing anything, the titleView of UINavigationController default to the title of the UIViewController.
Mine is not the case and I wonder why?
I set the title of the UIViewController in the story board to #"Nearby". I confirm that it's indeed the title in viewDidLoad
- (void)viewDidLoad
{
PO(self.title);
PO(self.navigationController.title);
Produce
self.title: Nearby
self.navigationController.title: (null)
I think I can programatically force my way and set the titleView to a UILabel with my title but I am not sure that would be the right way to do it.
I wonder why self.navigationController.title is not automatically set to self.title? If so when should it be set and where?
By the way, I added this line:
self.navigationController.title=self.title;
That doesn't help.
Update: Changing the NavigationItem Title Works. But that's awkward. Also how do I change that programatically?

instance variable in NSManagedObject class acts like a class variable?

IOS 5 only, with ARC. In my Core Data model class:
// Planet.h //
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Planet : NSManagedObject
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSNumber *diameter_km;
#property (nonatomic, retain) NSNumber *mass_kg;
-(void) setVisited:(BOOL)flag;
-(BOOL) isVisited;
#end
// Planet.m //
 
//#import "Planet.h"
#implementation Planet
 
#dynamic name;
#dynamic diameter_km;
#dynamic mass_kg;
 
BOOL visitedByHumans;       // not a core data entity; just an ivar
 
-(void)setVisited:(BOOL)flag {
    visitedByHumans = flag;
}
-(BOOL)isVisited {
    return visitedByHumans;
}
 
#end
I use MagicalRecord to create "Venus" and "Mars". In my view controller, I use labels and buttons to test the above. Testing shows that when I "visit" Mars, Venus also becomes visited. If I switch the ivar visitedByHumans into a non-Core-Data property, it works as expected. So I'm no longer 'stuck', but I want to understand the ivar thing.
vistedByHumans is not actually an ivar, but a global variable of your subclass Planet. So, any and every "planet" instance will appear to be visited regardless of which instance is actually visited. If you want to make it an actual ivar, you need to add a #property to your #interface much like name, diameter_km, and mass_kg (although, those three of course were generated for your models). e.g.:
#property (nonatomic,assign,getter=isVisited) BOOL visited;
and in your implementation:
#synthesize visited=visitedByHumans;
or just
#synthensize visited;
Since you appear to be using those methods (visited and setVisited:) anyhow, and not really directly accessing visitedByHumans.
Also, be sure to remove the line of code
BOOL visitedByHumans;
and the two method definitions isVisited and setVisited:. They will be generated for you when you #synthesize'd them.
It's impossible to be sure based on the information you've presented. Your description doesn't match the code-- despite what you say, visitedByHumans is most definitely not an instance variable in that code. This then makes me wonder what the code looked like back before you switched it away from using Core Data for visitedByHumans. Basically, you explain that the code wasn't working right when you were using Core Data, but then present entirely different code that doesn't actually use Core Data. I don't know what you were doing when you were trying to use Core Data for this property so I can't tell what you might have been doing wrong. If that declaration of visitedByHumans was in the code at that time, it was almost certainly screwing things up for you. Likewise, if you had setters in a managed object subclass that didn't call super's implementation, you'd get bad results. But if you want to know why your Core Data code wasn't working, paste that code, not some completely different code. Don't make people guess what you're up to when you ask for help.

How do i create a UITextView in main UIView from a UIButton Within UIPopover?

I'm trying to create a UITextView in my Main UIViewController when a UIControlEventTouchUpInside happens with my UIButton which is in a UIPopoverController.
I tried to use a delegate protocol to allow my button to be referenced within the Main viewcontroller.m but I don't think I have been doing it right. I will also mention I've created the UIButton and UITextField programmatically in a UIView subclass for the UIPopover.
The view controller that you display in the UIPopoverController should look something like this:
#interface MyViewControllerForPopover : UIViewController
#property (weak) UIViewController *viewControllerInWhichCreateTheTextField;
...
#end
Meaning that you could keep a weak reference to the view controller in which you want to add the text field. The button you generated in this MyViewControllerForPopover could do something like:
- (void)createTextViewInConnectedViewController:(id)sender {
UITextField *myTextField = ...;
[self.viewControllerInWhichCreateTheTextView.view addSubview:myTextField];
}
The key concept is that you want to have a weak reference (to avoid retain cycle) to the view controller you wish to alter. Even better if that view controller has a method to actually add the text field itself. Hope it helps!

Adding custom UIView to UIViewController in - (void)loadView (Objective-C)

I am taking a programming class (for noobs) and I need to create the UIViewController graphViewController's view programmatically (without interface builder).
The view is simple, it only consists of an IBOUtlet which is an instance of a UIView subclass called GraphView. graphView responds to several multitouch gestures for zooming and panning and what-not, but I handle all of that stuff in - (void)viewDidLoad.
I am doing just the creation of the self.view property and graphView in the code below:
- (void)loadView
{
UIView *gvcView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = gvcView;
[gvcView release];
GraphView *aGraph = [[GraphView alloc] initWithFrame:self.view.bounds];
self.graphView = aGraph;
[aGraph release];
}
When I run the app I do not see the graphView view in there. I just get a transparent view which shows the "My Universal App" label. I'm stumped. Please help.
Let me know if you need additional code.
Thanks!
Update: Big thanks to BJ Homer for the quick fix!
had to do the following:
add this line of code: [self.view addSubview:self.graphView]; at the end.
I was also getting this strange bug where graphView was showing up as completely black. This line of code fixed that: self.graphView.backgroundColor = [UIColor whiteColor];
And that's it!
Final question: Is the default background color black for a custom UIView?
Thanks again!
[self.view addSubview:self.graphView];
Until you add your graph view to a parent view, UIKit doesn't know where to display it. self.view is special, since that's the property that -loadView is supposed to set. That view will automatically be added to the screen. But your graph view is just floating off in the ether until you add it somewhere.