Practical efficient usage of IBOutletColletion - iphone

How does look the practical usage of IBOutletCollection? Unfortunately Apple documentation mentions it briefly without giving an wider idea of usage. OK, it maintains one-to-many relation with IB, but how to access and use particular objects efficiently? With TagName? How to ensure the order of objects?

I've recently used this to easily initialize a grid of labels. I have a n by n matrix of labels on a view, and reference each one individually (via an IBOutlet) in order to display relevant data. However when the view first loads I wanted to control the default text that displayed in all the labels. Initially i wanted a dash to display, but since this is for a client I wanted it to be easy to change. The view contents have and continue to change over time, per client requests.
Instead of writing N line of code, I created an IBOutletCollection and accomplished the same results in 4 (#property, #synthesize, and for loop). YMMV but I found it very useful in this situation.

Read again this section in the Interface Builder User Guide.
IBOutletCollections are actually just NSArrays you can connect to more than one object in IB. All the objects you connected end up in this array and can be accessed from code like any other object in an array.

I used it to minimize code. I have a range of UIViews that should react on "touch up inside" events of some UIButtons (custom mode).
I gave all UIButtons a tag (lets say 1005 to 1010) and all UIViews the same tag as the UIButton they shall respond to.
Then I connected the UIViews with the collection in Interface Builder. All UIButton touch up events go to the same function in my controller. This function gets the tag of the sender object, iterates through the NSArray list (of "IBOutletCollection(UIView)") and compares the tag. Everytime it hits, the appropriate action is done.
It is a pity that NSArrays seem not to hold the order...

Related

How BehaviorRelay.accept works in rxswift

I am drawing a tableview via BehaviorRelay.
Currently, I am using the code below as a way to add data.
viewModel.user.append(Person(name: "king", phoneNumber: "12341234"))
viewModel.personObservable.accept(viewModel.user)
I wonder if this code changes the user itself so that the whole tableView is redrawn.
If so, what method can I use to change only the data I added?
The code presented causes the personObservable (which is actually a BehaviorRelay apparently,) to emit a next event that contains an entire array of Person values, not just the latest Person added. Importantly, it's not emitting the viewModel.user object (at least not conceptually) but an entirely different object that happens to be equal to viewModel.user.
The default dataSource, the one that you get when you call items with anything other than a DataSource object, will call reloadData on the table view. This doesn't cause "the whole tableView" to be redrawn though, but it will cause the table view to query the data source for all of the visible cells, even if they haven't changed.
If you only want the table view to load the new cell, then the data source object needs to be smart enough to compare the new array with the array it's currently displaying so it can figure out which values are different and add/remove/move cells as appropriate, instead of just calling reloadData. As #Sweeper said in the comments, the RxDataSources library contains a set of data source classes that have that logic built in. If you wanted to reinvent the wheel, just write a class that conforms to both RxTableViewDataSourceType & UITableViewDataSource and implement the diffing yourself.

nil error when attempting to set textfield placeholder, segment uiview

xcode v:9.2
I am trying to load user information from the database to set as placeholder text. I have tested this code on a simpler project that does not have segment views, and it works fine. I did some research and I think it might be a hierarchical issue. I am struggling to understand how I can make the textfield values load so that the locations they point to are connected when I try to access them and set placeholder values.
GetCurr retrieves database values and sends them to completion handler function to write placeholder value. When run, "setPH = nil"
Calls GetCurr for email
Completion handler that sets placeholder text
loadUserView should tell when to load the values of this particular segment
I know it's not my IBOutlets because they are all connected and as previously said, this code works perfectly fine in a simpler app that does not have segment views.
I figured it out! I connected the segments to uiviews that had their own uiviewcontroller class, as subclasses of the parent base class. It also makes my code cleaner and prettier!
Useful:
https://docs.swift.org/swift-book/LanguageGuide/Inheritance.html
https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/

View-based table bindings in Swift

I'm trying to set up a view-based table in Swift using bindings. All of the examples I've seen use a datasource/delegate setup.
I have an array of Flag objects which has two properties - flagName: String and flagImage: NSImage. I have an NSArrayController managing this array.
If I set up a cell-based table, and bind one column to arrangedObjects.flagImage and the other to arrangedObjects.flagName, I get a table displaying images and names, and I can use the array controller's add and remove methods, so there are no problems with my datasource or my array controller.
I have been following the instructions in Apple's TableView Programming Guide to bind my view-based table to my array controller:
tableView Content binding: FlagController.arrangedObjects
textField Value binding: TableCellView.objectValue.flagName
imageView Value binding: TableCellView.objectValue.flagImage
(IBs autocomplete is not happy with the paths for objectValue.flagName respectively flagImage; it doesn't feel that there should be any completion whatsoever and says it can't resolve the path, so it looks as if the problem is with the tableView's content.)
If I do this, my table has a number of rows that corresponds to the number of elements that my array controller is managing at that moment (I have two simple setups, one object vs. 50 objects, so it's clear that something is bound). What I don't get is a display; and selecting a table row does not seem to send back a message to my flagController.
What am I missing? Has anyone been able to make this work? I've had no problems with other bindings in Swift so far, but I'm starting to think that the sudden reappearance of datasource examples is not unrelated to this.
It sounds like you've failed to implement the delegate method -tableView:viewForTableColumn:row:. That's a common cause of blank tables.
You don't actually have to implement that if you make sure the identifier of the table column and the identifier of the table cell view are the same in IB.
Otherwise, the method can just do this:
- (NSView*) tableView:(NSTableView*)tableView viewForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
return [tableView makeViewWithIdentifier:#"TheIdentifierOfYourTableCellView" owner:self];
}
(It could also do more, if desired.)

Model-View-Controller in practice on iPhone dictionary app

I'm a new developer creating a simple "dictionary" app for personal use and my question is about how to properly implement the Model-View-Controller design in my particular situation. Please bear with me for the necessary background:
I want to be able to hit a button and have a label display a word on one side of the screen, and to have another label display a list of associated words on the other side.
For instance: when I hit the button I want the main label to display "cats" and for the list to display "tiger", "snow leopard", "lion", etc. The output would be random: the label displayed would be random and the list would be scrambled.
I've achieved this output in the Xcode 4.3 console through storing each list in an NSMutableArray, and using an NSDictionary to hold all of the NSArrays. Here is the code:
//creates lists
NSArray *catList = [NSArray arrayWithObjects:#"Lion", #"Snow Leopard", #"Cheetah", nil];
NSArray *dogList = [NSArray arrayWithObjects:#"Dachshund", #"Pitt Bull", #"Pug", nil];
...
//creates dictionary and stores lists values with dictionary keys
NSMutableDictionary *wordDictionary = [[NSMutableDictionary alloc] init];
[wordDictionary setObject: catList forKey:#"Cats"];
[wordDictionary setObject: dogList forKey:#"Dogs"];
...
//randomizes selection of dictionary key
NSInteger keyCount = [[wordDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
//displays selected key, which is the main word
NSLog(#"%#", randomKey);
//selects array list corresponding to key
NSMutableArray *randomlySelectedArray = [wordDictionary objectForKey:randomKey];
//shuffles the output of the selected word list array
for( int index = 0; index < keyCount; index++ )
{
int randomIndex = arc4random() % keyCount;
[randomlySelectedArray exchangeObjectAtIndex:index withObjectAtIndex:randomIndex];
}
//prints word list and removes displayed dictionary selection
NSLog(#"%#", randomlySelectedArray);
[wordDictionary removeObjectForKey:randomKey];
(I need to add code that does displays a main word and list one at a time, maybe using NSTimer, but this is what I've got so far.)
Using a single-view template in Xcode, I've been able to get the simulator to show a main word and a corresponding list by adding some of this code to the IBAction method of the button in my view controller implementation file. (Of course I changed NSLog to initWithFormat.) However, none of my randomization code works.
My question, finally, is how do I separate things so that they conform best to the MVC design? I'm thinking that: My button and my two labels constitute the view. My view controller is the controller, and my NSArrays and NSDictionary data are the Model.
However, I've been keeping all of my model data inside the view controller, which I'm pretty sure is wrong. I think that I need to figure out how to create a class for my NSArrays and NSDictionary to store my model data. Then I must manage to get my button & labels to display the desired text of my model data via my view controller. At least I think that's how MVC works.
I'm wondering if that understanding is correct and if anyone has any pointers on how to organize my model data most effectively to get my desired output.
Thanks very much for any help! I'm stuck!
Before starting to design an application based on MVC. We first need to know what these different components are and what MVC help us to achieve?
Why we use MVC?(Model-View-Controller)
Because it helps us in:
Separating responsibilites also leads to reusability
By minimizing dependencies, you can take a model or view class you’ve already written and use it elsewhere
Think of ways to write less code
While designing an application based on MVC, we should focus on above points.
Lets relate this 'Dictionary' application with real world dictionary.
A dictionary is composed of words, their meaning, pronunciation, examples, usage, antonyms, synonyms, indexes and other similar information.
When a user wants to look for a particular word he will use top-margin word for fast look-up. Once he found the right page he will go to that word and see its meaning, usage or other needed information.
Model Part:
Lets draw analogy between your application and what I described above.
In your application you will be having a class : 'Dictionary' which
will represent the real world dictionary. This dictionary is composed
of words, their meaning, pronunciation, usage and other information.
So we will need an array of words which will contain 'Word' object.
The 'Word' class will have all the information that we wish to provide
for particular word. You can also provide other attributes that you
can think of that belongs to Dictionary and add them to it.(Here we are talking about content only)
Now we need to think of different operations to be performed on this dictionary. The most basic operation are creating a dictionary and accessing it.
We will have a DictionaryCreator class which will add all the words that our dictionary will have. So this is another class
'DictionaryCreator'. Or we can put this creating logic in 'Dictionary'
init methods. But it will be helpful to have this class this will
enable the dictionary add-word features.
Once DictionaryCreator creates a dictionary, User will be ready to use it. So we will need to provide different operations that a user
can perform on 'Dictionary' as its methods. In our case we can
consider user is over controller, which in fact is controlled by real
user.
The above techique will help you to create a component that performs only its responsiblity and can be reused in other application or extended for future use.
*Always remember Model is the most reusable component of MVC design. So whenever you are in doubt about Model just go remind the words 'Model must be reusable'.
(Not aware of views or controllers)
So we have just finished Model part of the application.
View Part:
This depends on you, what interface you wish to provide to user. But lets again consider the real world Dictionary. A real world dictionary's content(information) is spread across several pages. This view helps us to view/access/mark/bookmark in dictionary.(Remember that here user performs all the operation and not the pages neither the dictionary). The pages have easy look-up word on top or bottom and some pronunciation guidance at bottom.
In your application you said "I want to be able to hit a button and have a label display a word on one side of the screen, and to have another label display a list of associated words on the other side."
Here we have again have multiple options to implement this, you can create view using Interface Builder and connection them with your controller. But then again this controller and View will be tightly coupled and when we wish to use similar interface somewhere else we will be unable to do so. So for reusability we will create another UIView class and create it with a new View XIB and load this nib. So in future if you need similar kind of view you can easily reuse(like cocoa-touch provides us UIView, UIButton etc.).
*View also tends to be a reusable component in MVC.
(Not aware of controllers, may be aware of relevant model objects)
Controller Part:
Now we have created view and model but how will they communicate? Controller will help them in this. A controller :
Knows about model and view objects
The brains of the operation
Manages relationships and data flow
Typically app-specific, so rarely reusable
*The points and definition I have taken from Stanford University Lectures[CS193P - Lecture 6
iPhone Application Development
Designing iPhone Applications Model-View-Controller (Why and How?) View Controllers]
Update:
Recently, I have come across another good lecture on MVC. It explains this design concept in much better way with very nice examples. It is available at iTunes U or you can directly go to first lecture by iPad and iPhone Application Development (SD) by Paul Hegarty.

Access UIView's textview from other view

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.