Storyboard user defined runtime attributes with enum - ios

Does anyone know if it's possible to set user defined runtime attributes in Xcode's storyboard with an enum's name (not value).
I tried String and Number types, neither of them works.
Setting it programatically is an option, I know.
In other words, for example I want to able to set the textAlignment attribute of UILabel to NSTextAlignmentCenter without knowing NSTextAlignmentCenter's real numeric value (1).

It is possible only if Xcode provides you with interface for that. For example, there're buttons to switch between NSTextAlignment for UILabel.
And, no, there's no way to set any enum values - as long as Xcode doesn't provide functionality like that for editing property lists.
It will become possible, when property lists will support enums

Related

Set defaultTextAttributes using User Defined Runtime Attributes?

Say you are setting
field
.defaultTextAttributes
.updateValue(20.0, forKey: NSAttributedStringKey.kern.rawValue)
(BTW you do that to space out text, like t h i s.)
in fact, is there a way to set that using User Defined Runtime Attributes,
right on the storyboard in Xcode?
No, there is not. User Defined Runtime Attributes works only where key-value coding would work, with a limited range of value types. A moment's thought will reveal that your code can't be expressed in that way.
You could, however, subclass to define a custom property and set it to 20 in User Defined Runtime Attributes, and respond with a setter observer to run the code you've shown. That way, different fields can have different kern values depending on a setting in the storyboard.
(If you're going to do that, you might as well make this property IBInspectable; IBInspectable effectively is User Defined Runtime Attributes, with a different interface.)

Can we access the objects in Storyboard by ObjectID

I have a bunch of static objects (UILabel, buttons, views) in multiple Scenes. They are not connected to any IBOutlet. But I'd like to access them at appdelegate (or first VC), and change their properties before it is loaded.
Anyway to do this?
EDIT: Adding my intention:
I actually wanted to make a custom "multi-language" app. I want to be able to change language from within the app. I can get a list of all the objects by applying built in localization of storyboard (Main.strings is autogenerated). Then I disable localization again. Then from this autogenerated file, I want to be able to connect it to a json data based on language that I select.
Of course you can. For example, you can use tags of UIView. Just set tags in Storyboard. It's easy but not so good. Another way to do this is using Accessibilities. Enable and set for it in Storyboard.
And then you can access it by accessibilityIdentifier property.
I will post my choice of "solution". So what I did was make use of accessibilityIdentifier to set the "key" for the multilanguage phrase translation purpose.
And I make use of the UIView+Recursion class (you can find this simple class somewhere in SO), and basically iterate all the objects in a particular Scene and if the text matches, set the key in accessibilityIdentifier property (either in viewDidload or viewWillAppear or viewDidlayoutSubviews).
This way you can have language changes "on-the-fly" within the app, without restarting.

What is the purpose of accessibility and traits?

I would like to find out the purpose of accessibility and traits.
What is the purpose of traits's list of properties list here.
An Accessibility Trait allows you to choose the best description for what an element in your application does.
accessibilityLabel
The accessibilityLabel for an element is read by VoiceOver, and is designed to be a quick, one or two word label for what the element is. For instance, a “share” button may have an accessibilityLabel of “Share”. An “email” button may say “Email”. You get the idea. The goal is to give a brief word or two to give the user an understanding of what the element is and/or does. To implement, just go ahead and set the #property on the element:
[self.saveButton setAccessibilityLabel:#"Save"];
accessibilityHint
The accessibilityHint is designed to be a more lengthy description to be ready by VoiceOver. For instance, in the case of the “save” button above, you may want it to say something like “Saves the current information and returns back to the list of articles.” The #property is set similarly to the accessibilityLabel:
[self.saveButton setAccessibilityHint:#"Saves the current information and returns back to the list of articles."];
accessibilityTraits
You don’t have to use this for common UIKit controls, as it comes by default with the traits you’d imagine. But check out Apple’s WWDC ‘13 session on Accessibility for iOS and you’ll see how they adjusted the traits for some buttons.
AccessibilityTraits can be OR’d together to return multiple options, or just return a single one. As with the others, you can override this in a custom subclass or set it via it’s #property:
- (UIAccessibilityTraits)accessibilityTraits {
return UIAccessibilityTraitsButton;
}
Check ThisLink for more information

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

iOS - Dynamic Type and Interface Builder

Trying to implement support for Dynamic Type and have an issue. I set the style I want to use on a label or something in Interface Builder. I register for the UIContentSizeCategoryDidChangeNotification, and in the handler, I set the label's font to ... what? How do I know what style to use? Shouldn't there be an accessor that lets me find that out? If not, I have to put it in 2 places, which means they'll get out of sync and I'll be annoyed. Any thoughts?
I don’t think this will satisfy you, but set the font to [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2 or whatever style you set in Interface Builder.
Ignore the setting in Interface Builder. It’s not even worth setting. Interface Builder is a (mostly) static representation of the initial state of your views, but this is Dynamic Type.
You could subclass UILabel to make it dynamic, and/or join us on the dark side of setting up views in code.
Since iOS 10, there's no need to follow this rationale because the adjustsFontForContentSizeCategory property allows an automatic scaling of the font sizes according to the content type size selected in the settings.
All the text styles are well defined in the Apple reference site and their size variations as well.

Resources