Say you have a class
class Example:UIViewController, UIScrollViewDelegate
{
at any point in the life of the program, there may be (say) four little scroll views which have embedded themselves in an instance of Example, so those scroll views have said
aScrollView.delegate = someExample
bScrollView.delegate = someExample
and so on.
Is that information, indeed stored somehow, with someExample?
Obviously that information is stored with aScrollView - but is it also stored with someExample? Is the delegate connection two-way or strictly one-way? Can someExample examine itself and determine all the scrollviews which have been delegate'd to someExample?
So, is there a way for someExample to list all the scroll views currently connected to it in that way??
The delegate property is just a (usually weak) reference in the object that holds it. For an object to keep back pointers to its "delegations", it would need to implement its own structure and do the bookkeeping for adding and removing itself.
Related
I am building an app in Swift. I am creating my views in an entirely a programmatic way. In some instances, I have a ViewController that instantiates custom views. In addition, I may have variables like "var User" which gets populated after an Alamofire network call and is used in various UI elements throughout the view controller. Besides declaring delegates as weak var, are there any other rules that apply?
Also, is there a way for me to figure out whether I have a strong reference that should be a weak one? What should I be looking for?
The basic concept behind reference counting in Swift is one of ownership. Objects should hold strong references to any other objects that they "own", in the sense that they're responsible for the lifecycle of the other object, either alone or in conjunction with other objects.
A lot of object reference graphs in a typical application are hierarchical - one object owns a bunch of other objects, which each have their own children, etc. For example, a ViewController owns its window, the window owns its views, each view owns its subviews, and each subview owns the images, strings, or other content it displays. These are all strong references.
Weak references will typically be used for references that don't imply ownership. The delegate example is a good one - in most cases, a view does not own the delegate. The delegate object has a lifecycle independent of the view. In many cases, the delegate will be the same object that created/owns the view in the first place, for example a ViewController.
You do not want a strong reference that goes from a "child" to its "parent". That creates a circular reference, and both the child and the parent will hang around in memory until the application exits.
In addition to delegates and other "backwards-pointing" references, you will also see weak references used in caches, where you want to quickly return an object if it's requested a second time, but the cache shouldn't keep the object in memory if nobody's currently using it.
To properly answer your question, we would need considerably more detail, (please ...) added to your original question.
I would frankly caution you that "there are no rules" with regards to any issue as fundamentally "touchy" as weak references. Be especially careful not to "follow rules," imagining that thereby you will "be 'safe,'" when other aspects of your application's design do not clearly call for their use.
A "weak" reference is defined as a reference from one thing to another which, you assert, "is not sufficient to cause the referenced object to not be garbage-collected." If the memory-manager does decide to "reap" the object, it is supposed to set your "weak" references to NULL. It can do this at any time will do this at the most-inconvenient time.
One possibility worth contemplating in your application design is to use properties, backed by "getter" routines, instead of actual variables. Or, instead of storing a (weak ...) reference to something, put it into some sort of a "collection" and store its id. Yes, various forms of "getter routines" will be executed each-and-every time, but in the long run that might be more reliable than relying too-much on the memory manager. If you know that "all of the code, wherever situated," will have to pass through "this 'getter' routine," you can concentrate your bug-avoidance efforts at that one deliberate pinch-point.
I'm trying to pass int variable to UITableView through UINavigationController (I'm using xcode 4.3) So I created 2 classes (PartsTableViewController that is "UITableViewController" and PartsNavController that is "UINavigationController"), I want to pass the variable from my current class to PartsTableViewController and then open that table with its Navigation controller that contains the title bar , so I wrote in my current class the following code:
PartsNavController *partsNav = [self.storyboard instantiateViewControllerWithIdentifier:#"partsNav"];
partsNav.groupId = myGroupp.bg_id;
[self presentModalViewController:partsNav animated:YES];
and in the PartsNavController class I wrote in viewDidLoad:
PartsTableViewController *parts = [self.storyboard instantiateViewControllerWithIdentifier:#"Parts"];
parts.groupId = groupId;
[parts.tableView reloadData];
and in PartsTableViewController I wrote in viewDidLoad:
NSLog(#"This is group: %d", groupId);
but when run, it generates the output 2 times,
This is group:1
This is group:0
first time is the value that I sent and the second time it outs 0 , I just want the value that I sent, not 0
how can I prevent this and get just the value that I sent ????
I want to pass from (MaktabatyTableViewController) to (PartsTableViewController) without using segue
The better way to do what you want is to push second TableViewController in existing UINavigationController. The easiest way to do that is to create that NavContr in StoryBoard and than to TableViews and connect it's cell with leading view controller with segue. And than use method below:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *destViewController = segue.destinationViewController;
destViewController.integerValue = value;
}
I want to pass from (MaktabatyTableViewController) to
(PartsTableViewController) without using segue
There are (at least) two strategies you can choose from:
Direct communication: People often ask how to communicate between two objects, and it almost always boils down one of the objects having a reference to the other (and sometimes vice versa). To send a message to an object, you need a pointer to that object; if you've got the pointer, there's no mystery about how to communicate. Thinking about it in those terms helps you think about the issue a little differently: instead of the immediate "how do I send a message to that object?" you can instead focus on the relationship between the two objects. How was each one created? Is one of the objects the parent of the other? Is there some common parent object that can provide a pointer? How should the objects be related, if at all?
Indirect communication: Sometimes instead of having two objects communicate directly, it's more appropriate to route the communication through some intermediate object. For example, your MaktabatyTableViewController might send a message to its delegate, and the delegate could then pass the information on to PartsTableViewController. A much more general solution is to use notifications: MaktabatyTableViewController could post a notification that PartsTableViewController listens for. The intermediate object in this case is the notification center. Either way, the advantage that you get with indirect communication is that neither object has to know about the other. That reduces coupling between the two classes and makes them both more flexible and more reusable.
From what I can see in your question, I'd suggest using notifications.
Hello I have an app with 2 views.
The cybeeview and the moreview.
I use the cybeeview to do some calculations and I want to present them in the second view.
How can pass the data from cybeeviewcontroller.m to the moreviewcontroller??
Good way would be to use delegation. You can either write your own protocol, or implement - textViewDidEndEditing: inside moreviewcontroller. You will also need to set up the delegate:
cybeeviewcontroller.yourTextView.delegate = moreviewcontroller;
//those controllers are instances of their respective classes
Nonetheless it must be said that unless it is a minor and unimportant calculation you're doing, it's fair to say that you are not doing it correctly. You should be setting your model values and pass model around. You can get more information in documentation, look for Model-View-Controller design pattern.
I have a BankAccount model class that contains data like account number, bank name, transactions, etc. The transactions are each instances of the Transaction class and contained in the transactions NSArray.
I also have a BankAccountView that displays all this in a single view. Right now I'm passing all the data as separate variables (ie. bankAccountView.accountNumber = bankAccount.accountNumber, bankAccountView.bankName = bankAccount.bankName).
The problem/dilemma arises when I need to pass the transactions to the view. I learned to keep the model and view classes separated, so I assume it's not a good thing to just pass the transactions array of BankAccount to BankAccountView, since that array contains instances of the Transaction model class.
So what I'm doing now is this: I take each Transaction instance, translate it into an NSDictionary, then set bankAccountView.transactions to an NSArray containing those dictionaries. It works and I feel like it's keeping my model and view classes separate, but it also feels overly complex, like I'm writing a lot of code for someting that could be much simpler.
Is there a better way to do this? Thanks in advance.
I think you took it way too far already and should pass the whole BankAccount object directly. No conversion, no surroundings, just pass it all along to the view. The kind of separation you did (to me) feels a bit like shooting with cannons at flies...
My arguments:
your view is capable of displaying BankAccounts only, why not pass the object it's displaying?
this makes your interface very clear, only one property is needed: #property(...) BankAccount *bankAccount;
(EDIT) passing an object encapsulates the dependencies between all your properties. They ain't independent, they form a bank account. This should be visible.
no conversion is needed, the interface does not need to be changed if you extend the model
the very very strong division between model and view was needed only if your view was independent from the data it's displaying. There is no point in anonymizing a view that can display only one very specific type of data: a bank account.
All the conversion would only make sense if you compose your view of several reusable components. You don't seem to so this is simply unnecessary work.
MVC is still preserved: Model does not know controller or view, view does not directly know controller, controller passes data from view to model and reacts to actions.
If you do not want to pass the class directly, design a protocol that encapsulates all properties the view needs from a bank account object and have the class BankAccount implement it. However, this only makes sense if you (plan to) pass different kinds of classes as data to the view. So different that these classes don't share a common superclass capable of all these properties. If there is only this simple class or inherited classes, stay with the simplest possible solution: pass the account directly.
In order to be able to trigger redraw on changes, I suggest you use Key-Value-Observation. It's a very clean way to keep the anonymity and having to write very few code. In your init method in the view do the following for each property you'd like to observe:
[self addObserver:self forKeyPath:#"bankAccount.<property>" withOptions:0 context:#"redraw"];
Then you implement observeValueForKeyPath...:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == #"redraw") {
[self setNeedsDisplay];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
I find this to be a very clean method with very little overhead, which I happen to heavily use in my own projects.
The way I look at the MVC paradigm (and remember, it's just a paradigm — it's open to interpretation) is the Model knows nothing about the view and the view knows nothing about the model. They should not directly interact; your view should not have an instance of your model, strictly speaking.
This is where the controller becomes important. I'm going to pretend your BankAccountView has some labels to display the account info, and maybe a tableview to show all account transactions (let's pretend, just for illustration). So then you would have something like this:
MyBankAccountViewController is a UIViewController subclass (the C in MVC), whose view is an instance of BankAccountView. Your view controller also has an instance of a BankAccount. At an appropriate time (such as -viewDidLoad), you'll want to populate your view (and its subviews) with the information in your BankAccount model (self.bankAccountView.accountNameLabel.text = self.myBankAccount.name or something).
MyBankAccountViewController would also act as the delegate and datasource to the tableview in your view, providing it with cells listing information about the account's transactions.
When something happens in your view that needs to change your model (for example, the user presses a "Close this account" button), the "event" would be sent from the view to the controller (either through delegation, target action, or some other mechanism you choose). The controller then decides what to do, such as [self.bankAccount closeBankAccount];.
Like I said, this is just how I interpret MVC (I view it strictly and pedantically), and it might complicate your code more than just passing the model in directly. If you're just going to be using this view in exactly one place, and never plan on reusing it, then passing in directly would likely be simpler. Just keep in mind that comes at the expense of making it more difficult to reuse in the future (which is one of the key selling-points of MVC: your models and your views should be reusable; your controller won't be).
Maybe a FAQ at this website.
I have a TableViewController that holds a form. In that form I have two fields (each in it's own cell): one to select who paid (single selection), and another to select people expense is paid for (multiple selection).
Both fields open a new TableViewController included in an UINavigationController.
Single select field (Paid By) holds an object Membership
Multiple select field (Paid For) holds an object NSMutableArray
Both vars are being sent to the new controller identically the same way:
mySingleSelectController.crSelectedMember = self.crPaidByMember;
myMultipleSelectController.crSelectedMembers = self.crSelectedMembers;
From Paid for controller I use didSelectAtIndexPath method to set a mutable array of Memberships for whom is paid:
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark) {
[self.crSelectedMembers removeObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
else {
[self.crSelectedMembers addObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
So far everything goes well. An mutable array (crSelectedMembers) is perfectly set from child view.
But...
I have trouble setting Membership object.
From Paid By controller I use didSelectAtIndexPath to set Membership:
[self setCrSelectedMember:[crGroupMembers objectAtIndex:indexPath.row]];
By NSlogging crSelectedMember I get the right selected member in self, but in parent view, to which ivar is pointed, nothing is changed.
Am I doing something wrong? Cause I CAN call the method of crSelectedMembers, but I can't change the value of crSelectedMember.
If I understand your question, the most likely cause is an improper property declaration.
If you want to pass values from one object to another using each objects properties, then you need to make sure to use assign to ensure the properties in one object are pointing at the same instances as the property in the other object.
So in your topViewController you have a property:
#property (nonatomic,retain) NSString crSelectedMember;
Then in your child view controllers you have:
#property (nonatomic,assign) NSString crSelectedMember;
This forces the value into the exact object in the parent controller.
However, this is a very fragile way to pass data between viewControllers. As your app becomes more complicated, it will be impossible to track all the passed data. (Worse, if you run into memory limitations, the parent view controller may unload and not even exist when you try to pass data to it.)
Instead, you should have a single custom object devoted to holding your data. Each view controller should query that object for the data it needs and should write any changes back to that object. The view controllers never communicate directly. This technique allows you to control the data in one specific location instead of spreading it out all over your code and it scales well. You can add an arbitrary number of view controllers to you app without having to worry about tying them all together.
See this post for details: iPhone: How to Pass Data Between Several Viewcontrollers in a Tabbar App