Reloading UITableView from another class? - objective-c

This is a question rather many people have asked, especially here on StackOverflow.
Reloading the data on the table view is easy, [self.myTableView reloadData];, myTableView is the instance of my UITableView, since I am using a UIViewController instead of a UITableViewController.
I want to reload the table view from another view controller after I have updated the data (from Internet). The data is contained in a property list. I have tried using protocols, notifications and some other things like putting it in viewDidAppear:. Nothing have worked for me.
Is it something I haven't thought about or have I just done some of the methods wrong? The help is much appreciated!

If you want access to a UITableView object, or just about anything else for that matter, from another class, you can make it accessible using a property:
ClassA.h
#interface ClassA {
UITableView *tableView;
}
#property (nonatomic, readonly) UITableView *tableView;
#end
ClassB.m
- (void)reloadTableInOtherClass {
[classAVariable.tableView reloadData];
}

Using observer pattern + notification is a good way. And to let your view controller decide when to reload data is also a good practice.
Why notification does not work. Did you use addOvserver: ?

Related

What Happened to Core Data Bindings?

I've been out of the loop for a while, but it used to be you could use Interface Builder to add an NSArrayController, set it's mode to Entity, and bind the managedObjectContext to the MOC of the AppDelegate. That doesn't seem to work anymore.
I've read through the documentation, (of course it's very possible I missed something) but I haven't yet found a way to bind my Array Controller to my Core Data stack. Somewhere along the line things got "simplified". What is the preferred way to get objects from Core Data to my NSTableView?
For more details, I currently have a fairly empty non-document project, no storyboards, with no modifications to the App Delegate, but I did add a property on my App Controller to access the MOC:
#interface JBAppController : NSObject
#property (nonatomic, readonly) NSManagedObjectContext* managedObjectContext;
#end
#implementation JBAppController
...
- (NSManagedObjectContext*)managedObjectContext
{
return [[(AppDelegate *)[[NSApplication sharedApplication] delegate] persistentContainer] viewContext];
}
...
I'll probably redo this once I understand what the bindings are missing, or if we aren't meant to use bindings anymore, however the right way to get the data to the tableview is.
Control-drag:
Control-drag to the property, configure the binding and click on Connect.
Bindings Inspector:
Configure the binding and turn on the Bind to checkbox.

How to organize classes in UIView/Subview responding chain?

I often heard, that it is not good to organize classes the way every class knows every other class.
So I try to let the classes that are as a property in other classes not know about their parents. But with UIView I can't make it happen.
The question comes from a more generic background, because the problem occurs not only on UIViews.
If I have a car as object with 4 wheels as 4 instance variables and when the left front wheel bursts. The left rear wheel should get a message. How should I design the system in a good way?
An example with UIView in Objective-C:
I have an custom UIView filling the whole screen. managing all the layout. Let's say only 2 subviews keep it simple.
#interface BackgroundView : UIControllerView {
CustomViewA *buttonA;
CustomViewB *buttonB;
}
#end
#interface CustomViewA : UIButton
#interface CustomViewB : UIButton
Now if someone presses button A, button B should do something (e.g. turn red).
There are several options I see:
Set the delegate of button A to button B, so all event of A goes to implementation file of B. Problem if not all events have to do with button B.
Create a singleton of BackgroundView and let button A get the property of button B or call a method in BackgroundView that does forward my call to button B. Problem if I want more than one Background, could create a even higher class to have the two BackgroundViews (doesn't sound nice).
Call parent implemented for UIViews and then like 2. call a method or change it directly. Problem when not using UIView, copy the functionality to other 'parent' classes ?
Is there a better way of solving such a problem? Or can I optimize one method greatly?
#Odrakir mentions Model-View-Controller here, and they're right -- that should be your first stop. In case it helps, here's how you might apply that pattern to your example:
You have a model class with a property color. In a document-based application, the document typically is the model. In a non-document-based application, it's common to hang the model off of the application delegate instance. For simplicity's sake, let's say we're in the latter case. You might have the following classes:
// "Model"
#interface MyModel : NSObject
#property (nonatomic, readwrite, copy) UIColor* color;
#end
// AppDelegate
#interface MyAppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, readonly, retain) MyModel* model;
#end
// "View"
#interface CustomViewA : UIButton
#end
#interface CustomViewB : UIButton
#end
// "Controller"
#interface MyViewController : UIViewController
#property (nonatomic, readwrite, assign) IBOutlet UIView* buttonA;
#property (nonatomic, readwrite, assign) IBOutlet UIView* buttonB;
- (IBAction)doActionA: (id)sender;
- (IBAction)doActionB: (id)sender;
#end
The basic pattern is this: Actions from the view trigger model-modifying actions by the controller (the target/action pattern). To achieve this, you would hook them up by connecting the action of button A to -doActionA: on the controller ("File's Owner" in IB) and (likewise for B). Then the action methods on the controller, when triggered, should modify the model, and invalidate any views that would need to be redrawn as a result of the model change. You might do this by plugging the views into IBOutlets on the controller and having the controller call [self.buttonA setNeedsDisplay]. Then, when your view draws, it should read, from the model, any state that it needs to draw correctly.
It's worth mentioning that on MacOS, you can eliminate the manual invalidation step by using bindings to link the view to the model. In that case, changes to the model will automatically invalidate the view. iOS/UIKit doesn't have bindings, so you have to do this invalidation by hand.
Probably all that logic belongs in a ViewController who knows everything about the views he controlls but the views don't know anything about the view controller or about each other.
Views should communicate with the view controller through delegation (or target-action) and is the view controller the one that should make decisions and maybe, forward messages to other views.
By the way, take a look at Stanford courses in iTunes University. I think it's the first or second class where they talk about MVC (Model View Controller). It's going to help a lot: https://itunes.apple.com/us/course/coding-together-developing/id593208016

Binding in Interface Builder

i am new to stackoverflow, so please be gentle with me.
I am currently working my way into objective-c and mac os x development and i am currently stuck at the simple task of binding a few objects together in a small project i am working on:
I have an object AppDelegate, created from a NIB file, containing a NSMutableArray. I wanted to access that array in another class derived from NSOpenGLView (created from the NIB File as well) to iterate the objects stored in it.
How can this be achieved in Interface Builder?
Thanks for your help.
UPDATE: Here is part of my AppDelegate code:
.h:
#interface AppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSMutableArray *_players;
}
#property (assign) NSMutableArray *_players;
Additionally i have a MyOpenGLView (implementing NSOpenGLView) where i want to access the objects from the _players Array.
Does your NSOpenGLView have an outlet pointing to your AppDelegate? If not, then you can either make one or use the answer from here.
[(YourAppDelegate *)[[UIApplication sharedApplication] delegate] uploadFiles:array]
(This assumes that AppDelegate actually refers to the application delegate.)
Apple tutorial on interface builder basics (including connecting outlets).

NSCollectionView inside another NSCollectionView

I have these two classes:
#interface Father : NSObject
{
NSString* name;
NSArray* listChildren;
}
#property (copy, readwrite) NSString* name;
#property (copy, readwrite) NSArray* listChildren;
#end
#interface Child : NSObject
{
NSString* nameChild;
NSImage* picture;
}
#property (copy, readwrite) NSString* nameChild;
#property (copy, readwrite) NSImage* picture;
#end
I'm trying to make a NSCollectionView filled with Father items, and for each father item's View i will have a name label, and another NSCollectionView filled with the (father) representedObject.listChildren items.
I've managed to create an external NIB file for the father NSCollectionViewItem's View to make things easier, but I'm not able to bind the child CollectionView to the representedObject.listChildren property. Actually, there is no problem in binding in IB, and at runtime the system is actually calling the property (I've added and getListChildren implementation and a NSLog call to make sure the property is being called). It seems that the inner CollectionView's won't load the items found in my NSArray* property?
It is driving me crazy, any ideas about what is going on?
Help please!!
I had the exact same problem and I found the solution!
I'm a complete novice to Objective C and Cocoa so I don't fully understand the reasons why this does not work exactly. Maybe somebody else can enlighten us.
In my first try I simply did everything in the default MainMenu.xib. You end up with two NSArrayController this way. Now apparently, as you suspected, the issue lies with the second NSArrayController for the inner items. It somehow doesn't get "copied" correctly. Extracting each NSView into its own .xib solves this issue.
Actually this discussion got me started in the right direction. I later discovered/understood that this is the basically the same idea #user493638 already hinted at.
Combining this knowledge with the tutorial here, on how to extract the views into their own .xib solved the problem for me!
Again I don't understand Objective C and Cocoa nearly enough to fully appreciate the underlying reasons for this behavior, who knows how exactly all this binding magic works under the hood...

Setting a property on a custom object through Interface Builder

I have a custom UITableViewController subclass which I use in two places in a nib file. What should I do if I want the two instances to have slightly different behavior? Of course in the code I can select one kind of behavior or the other based on the value of a BOOL, but how do I set that BOOL from Interface Builder, without having to write an Interface Builder plugin?
As of Xcode 6 there is a new way doing this. You can now give your view properties the attribute IBInspectable and then you can edit those properties in IB as you would with and standard view.
So for example:
#property (nonatomic, strong) IBInspectable BOOL
More details (also for the new attribute IBDesignable) in Apples documentation: https://developer.apple.com/library/ios/recipes/xcode_help-IB_objects_media/chapters/CreatingaLiveViewofaCustomObject.html
"User Defined Runtime Attributes" in the Identity inspector is probably what you're looking for. This seems to be new as of Xcode 4.2.
Unfortunately, there doesn't seem to be much (any?) documentation about this feature on the Apple Developer site. I was able to use it for a simple property set.
So far as I know, you can't set parameters in IB without writing an IB Plugin.
That said, you have two other options.
If it is as simple as a single BOOL, you're probably best off making it a property of the MyCustomViewController class and set it in code after you init:
customViewController = [[MyCustomViewController alloc]initWithNibName:#"CustomViewController" bundle:nil];
[customViewController setFunky:YES];
The other option is to create a protocol for a MyCustomViewDelegate. If you're not familiar with protocols, your header would look like this:
#class MyCustomViewController;
#protocol MyCustomViewDelegate
#required
-(BOOL)customViewShouldBeFunky:(MyCustomViewController*)customView;
#end
#interface MyCustomViewController : UIViewController {
NSObject<MyCustomViewDelegate> *delegate;
}
#property (readwrite, retain) IBOutlet NSObject<MyCustomViewDelegate> *delegate;
#end
Since it is an IBOutlet, you can wire up the delegate like any other delegate in Interface Builder.
Then call [delegate customViewShouldBeFunky:self] when you need to determine how your view should behave.
Have two subclasses is probably easier, and will be easier to document.
Here is an example of overriding properties and setting them in custom classes, this may help. The property code will work before awakeFromNib is called. So you may decide what you have to do based on the user's decision right in awakeFromNib.
https://stackoverflow.com/a/31094561/1699210