Changing UILabel's text - ios

I'm currently following CS 193P, and I'm on lecture 2.
If you've followed this class before, I'm where we just added a label to output the number of flips.
Here's the screenshot of the view and controller (original code from the lecture):
I notice the instructor is changing the flipsLabel's text from inside the setter for flipCount. But, I think it's easier/ more intuitive to just send a message to the flipsLabel object whenever touchCardButton method is being called. Here's the screenshot after modification:
Can somebody explain the reason why the instructor wrote it that way? He said "And here's another great use of getters and setters, which is to keep UI in sync with a property"

I started my iOS developer career from CS193P as well about 2+ years ago.
Just like KudoCC said above, if you use your method to set flipCount in 10 different places, then you will have to set self.flipsLabel in 10 different places as well. So, your method will have more lines of code while the professor's way is using less lines of code.
I personally think that it is the art of programming. We have different ways to achieve the same thing in programming. But, the less code you use in programming is usually the better way.

The content of self.flipsLabel only depends on flipCount property.
You may change the value of flipCount at more than one place afterwards, and if you work as the instructor said, you needn't update the content of self.flipsLabel every time you change flipCount.
You are in a simple user case which may not matter how to implement it, but if you are in a complex user case, you may change the value of flipCount at 100 places, in you intuitive way, you must add 100 times [self.flipsLabel setText:[....]], if you forget to add in one place, a bug is born.

The purpose of his code is: Everytime you set a new value for flipCount property, the text of label also changed. You don't need to set label text again. Your code will be clear, and easy to modify after.

Related

Where to put programatic constraints for MVC

I want to practice creating simple apps using no storyboard. I am able to do the constraints programmatically (slowly) but I want to also practice separating my code into MVC. Is there a particular place/method that I am supposed to write the programatic constraints? Or does it not matter?
Good discussion in the comments. My thoughts, based on that discussion?
With an understanding that the question is subjective, you place your constraints:
The earliest in a view controller's life cycle where they work.
As "close" to the view as possible.
If it's something common, make it as universal as possible.
Understand how your specifics fit into everything.
(Understand, the question isn't limited to constraints. It could apply to hierarchies, UI, even database tables when you get down to it!)
Sticking to constraints, and my answer....
(1) Use the UIViewController and UIView lifecycles.
Generally the view life cycle is loadView, viewDidLoad, viewWillAppear, viewWillLayoutSubviews, viewDidLayoutSubviews, and viewDidAppear. great SO answer detailing this.
I believe that loadView is too early for constraints, but not viewDidLoad - **provided you aren't expecting to know the frame size. While many say viewDidLayoutSubviews is the right place for that, I've found that viewWillLayoutSubviews most times works just as well. Either way, get your constraints set as soon as possible!
(2) Do it as close to the view as possible.
If you have subviews - I have a "ToolBar" class of objects - you want the constraints, at least as much as possible, to be coded inside the class. For instance, in my tool bar, it slides out, has buttons, and even rotates upon orientation. The only constraints not inside these classes is for orientation - that owner is (and I believe should be) the view controller instantiating it.
(3) Make it universal.
I plan to use this tool bar across a few apps. So the first thing I did was add it to a framework. This framework was needed because I had an app that I delivered a photo editing exension - and the "edit" screen is as much the same as possible. In the end I move all my constraints there. (At least as much as possible.) Anything that I believe is reusable.
(4) Understand the specific requirements of your app.
This should be obvious. If you need to code for various orientations, use arrays and activate/deactivate them. (YES, a common mistake is replacing them! That's setting yourself up for some major headaches.)
If you can keep things active, declare the constraint, set `isActive = true1, and forget about it. If you need to adjust that constraint's constant or multiplier, in the declaration name it and then where you need to alter it, do it.
My conclusion? Auto layout is a very useful tool - more so in code. But the placement of code is like asking "how does one code an OOP app for auto rentals" or " how does one design a database for auto rentals". It not just an art, there are many answers. These are the "rules" I try to follow - YMMV.
To get started with this style of development I recommend checking out Let's Build That App as he goes through very in-depth examples of setting up complex apps entirely in code, without storyboards.
The way he structures the constraints is using a custom implementation of UIView, that way your view code is separated from the ViewController. Then, in the viewDidLoad method you can instantiate your implementation of UIView with something like self.view = MyView().
I wrote a few apps like this. The major drawbacks are that it can become very difficult to make quick adjustments, and you really need to learn about all the different types of constraints you can use.
Here's a pastebin of some extensions I used when doing this. I hope this helps.

Xcode UI Testing [xcode7-beta6] - Asserting actual label values when using accessibility labels

The question is actually really simple:
Is there a way to assert the displayed value from a specific label (e.g. UILabel) when using an accessibility label on this object?
As far as I see it, all the assertions (e.g. XCTAssertEquals) made in the examples, be it from a WWDC Talk or Blogposts, are only checking if an element exists for a query like XCTAssertEquals(app.staticTexts["myValue"].exists, true) or if the number of cells in a table is correct XCTAssertEquals(app.tables.cells.count, 5). So, when avoiding accessibility labels it's possible to check if an object has a certain value displayed, but not which object / element.
And when using accessibility labels, it robs me of the opportunity to query against the displayed values, because app.staticTexts["myValue"] will now fail to deliver a result but app.staticTexts["myAccessibilityLabel"] will hit.
Assuming I want to test my "Add new Cell to Table" functionality, I can test that there is really a new cell added to the list, but I have no idea if the new cell is added at the top or the bottom of the list or somewhere in between.
For me, an easy way to check if a specific element has a certain value should be a no-brainer when it comes to UI Testing.
It is possible that due to the missing documentation I might overlook the obvious. If so, just tell me.
Be sure to set the .accessibilityValue property of the UILabel whenever you set its .text value. Then in UITest, you can test the accessibility value like this:
let labelElement = app.staticTexts["myLabel"]
...
XCTAssertEqual(labelElement.value as! String, "the expected text")
I think you are asking a few different things, so I will try to answer each question individually.
Is there a way to assert the displayed value from a specific label (e.g. UILabel) when using an accessibility label on this object?
In short, no. UI Testing works by hooking into accessibility APIs, so you are limited to querying for objects based on that. You can, however, check the -value property of certain elements, such as controls. This is used to test if a switch is on or off. Note that these boil to down using accessibility APIs as well, just a different method (-accessibilityValue over -accessibilityIdentifier and -accessibilityLabel).
...but I have no idea if the new cell is added at the top or the bottom of the list or somewhere in between.
To interrogate an XCUIElement for its frame you can use the new XCUIElementAttributes protocol which exposes -frame. For example:
let app = XCUIApplication()
app.launch()
app.buttons["Add New Cell to Table"].tap()
let lastCell = app.cells["Last Cell"]
let newCell = app.cells["New Cell"]
XCTAssert(newCell.exists)
XCTAssert(newCell.frame.minY > lastCell.frame.maxY)
For me, an easy way to check if a specific element has a certain value should be a no-brainer when it comes to UI Testing.
If you think of everything in terms of accessibility this becomes a non-issue. UI Testing can only interact with your elements via accessibility APIs, so you must implement them. You also get the added benefit of making your app more accessible to user's with those settings enabled.
Try setting both the -accessibilityLabel or -accessibilityIdentifier for the cell to the displayed text. UI Testing can be finicky as to which one it uses.
It is possible that due to the missing documentation I might overlook the obvious. If so, just tell me.
XCTest and UI Testing don't have any official documentation. So I've gone and extracted my own from the header files exposed in the framework. Note than even though they were pulled from source, they are unofficial.
XCTest / UI Testing Documentation
What works for me is to set the accessibility identifier of the UILabel to let's say MyLabel.
func myLabelText() -> String {
let myLabelUIElement: XCUIElement = self.application.staticTexts["MyLabel"]
return myLabelUIElement.label
}
Tested with Xcode 8 and iOS 10
From the apple forums it looks like it is possible to get the value of the label:
The only way I've found is to not set an Accessibility Label, but use identifier instead. Then XCUIElement.label will change to match the current text of the label.
However there is a gotcha: if you have previously set Accessibility Label in XC, and remove it, an entry setting the label to "" remains in the storyboard. In this case, not only will calling .label will return "", but you won't be able to query for the label by it's text!
The only thing you can do is delete and re-add the label, or manually edit the xml.
lastobelus - https://forums.developer.apple.com/thread/10428

Using custom NSView/UIView subclass from XIB?

OK, this may sound very basic (especially for someone who has written tens of thousands of Objective-C code), but I've always tried to avoid all this... or just tweak existing solutions. The result? I've never learnt how to do something simple like that.
So, here's my ultra-simple scenario:
I want to create a custom NSView (let's say a simple view with an image and a text in it), which I'll be able to assign in the Interface Builder (take an NSView element and set its class to MYCustomView - that's all - nothing more complicated)
I know I can write an NSView subclass and have it draw all my elements programmatically in drawRect: and all this - but I most definitely don't find any point in that.
What I do want is to simply draw the view in the Interface Builder (in our example, with a "placeholder" image and textfield), be able to use it as the "basis" of our NSView subclass, and also maintain pointers to the two elements in the view so that I can programmatically access them.
I know it's doable - I'm not asking about that. What I need is an ultra-simple walkthrough. Is there anything you can point me to?
Rephrasing the question in a... one-liner:
How can I replace the programmatic approach (seen in like 99.9% of NSView subclasses) in drawRect:, with a layout taken from a XIB?
P.S.
(A) Trust me, it must have been the 100th time I've been reading about NSViewControllers and all these, but not having used them, probably means that I still haven't found the point in using them...
(B) Please, don't shoot me with "what have you tried" questions. In the course of time, I've tried loads of things and at times I've somehow made it. However, it always feels like a crappy, messed up thing I just managed to get working. Nothing more, nothing less. All I want is to know if there is a simple tutorial on the above simple scenario.
(C) If I get an actual explanatory answer to this one, I guarantee I'll re-post it myself. You simply can't believe how many seasoned Cocoa developers have serious trouble dealing with this...
I've always wanted "custom" Storyboard classes as well!
This may not totally answer your question but this is just how we do it now, in iOS: just use container views.
Full extremely long tutorial: https://stackoverflow.com/a/23403979/294884
Everything's a container view in iOS now.
What we do is just have a scene, and then duplicate it: then change the colors or whatever as you describe.
Here's a literal example from the storyboard that was open behind this browser window!
Notice the small class/scene thing, we just copy it. Notice in the example it is slightly customised, just as you say. They are all the same class (it happens to be caled "BookBist") {"bist" == "bouncy list" btw}
Then as I say container views are the secret because, well, it's for exactly this purpose, it's why apple finally introduced "container views".
(BTW on that long container view tutorial. Search down to What if you want (say) a table controller or a page view controller instead of a UIViewController? it's a critical trick when making container views! Ridiculously Apple gives you a "default" VC when you drag in a container view; of course you never want that; in the example at hand I put the small BookBist scenes connected to the container views wherever they are needed.) Example...
Now, I 10000% understand what you are asking and have always wanted to know the answer myself!
For use HALF the answer, is, as I say, "copy the scene" so that works perfectly in modern storyboard. I appreciate that sucks, because what you want is a prefab, like in any game engine such as Unity3D, right? Me too!
But do note that THE OTHER HALF of your answer is certainly "container view magic" - "everything's" a container view now in iOS, indeed Apple finally put them in to make a rational way to do exactly the sort of thing you describe.

Custom UITextInput implementation not showing multi-stage input suggestions

I have a custom UITextInput-based text editor. It works very well, except for multi-stage input via marked text.
My marked region renders correctly, and marked text is inserted, but the candidate list above the keyboard is blank.
For example, here is the Japanese (Kana) keyboard showing suggestions on a standard UITextView:
And here is my custom editor displaying the same marked text:
I have spent several days debugging this issue and have found that the cause is private class UIKeyboardImpl returning NO for the method delegateSupportsCorrectionUI
If I override this method in a category on UIKeyboardImpl and return YES instead, then multistage input suggestions correctly display for my text editor. However this does not address the underlying cause of the problem (and it's not usable).
I have also looked very closely at Apple's SimpleTextInput sample code. This implements a basic Core Text editor. SimpleTextInput correctly displays multistage input suggestions, however I cannot seem to find a single difference in its implementation of UITextInput that causes it to work and mine to break.
(In fact, I am unable to "break" the SimpleTextInput sample's ability to display multi-stage input. Which leads me to think that my focus on the UITextInput implementation is the wrong track. And it is something else altogether.)
Okay, this is a bit embarrassing. I just now noticed:
#property(nonatomic, readonly) UIView *textInputView
Discussion
The view that both draws the text and provides a coordinate system for
all geometric values in this protocol. (This is typically an instance
of the UITextInput-adopting class.) If this property is unimplemented,
the first view in the responder chain is selected.
In the documentation.
I had stupidly #synthesize'd this property and forgot about it, meaning my UITextInput implementation was returning a nil textInputView. Simply leaving it unimplemented chooses the first view from the responder chain as described, which provides the text system with the necessary coordinate system to handle auto-correction and multistage input suggestions.
This was after three days of debugging. Now I feel stupid.

Select a range in UISlider

i asked me whether it is possible if i can create a uislider who has 2 handles to select a range. Just like here:
The problem i am facing is that i dont want to use a custom UIControl Subclass. I need a UISlider subclass or a other solution for this problem, because a lot of the code is based on UISlider specific propertys etc. So is there any possibility to achieve this ?
Look at the following example:
http://www.cocoacontrols.com/platforms/ios/controls/rangeslider
You can subclass UISlider, but it will be very difficult. Your class should offer quite some new properties, and the old ones won't make much sense at all.
Not sure how your code can be based much on UISlider specific things - as everything would change the meaning (i.e. ranges instead of one value).
If you really need a common base class, you could encapsulate ("has-a" relationship) the control in a custom class and let this handle the different types.
I implemented a similar control using a custom view, and it happened to be quite straight forward.
UISlider doesn't provide the functionality you're after, and subclassing UISlider probably won't work out. What would the value of such a control be? The value of a slider is a number, but you want it to be a range. Consider a custom control that duplicates the UISlider properties you need.

Resources