can I write Swift to bind UI stuffs in iOS by id - ios

Recently I am learning iOS developing by Swift.
I have some experience about Android development so I am super curios about :
Can I binding UI stuffs(etc button, label) by programable typing the id which I did in Android instead of using drag and drop
I have search couple key words in google but not finding some suitable answer.
Thanks.

Add your view to the storyboard or xib, at the utilities panel on the right select Show the Attributes inspector. Add numeric tag to your view just like the photo below.
Now in your view controller, you can get the view reference by using this code.
let button = self.view.viewWithTag(3) as! UIButton

Yes is it possible but it is not a recommended way, anyway you can use the tag property, and then you can refer to your UI object as:
if let myLabel = self.view.viewWithTag(120) as? UILabel {
myLabel.text = "some text"
}

Related

Performing UIAccessibilityCustomAction from UITests

I've got a subclass of UIView, let's say it's class DemoView: UIView { } which contains UILabel and UIButton. I needed to group it and add UIAccessibilityCustomAction so I've overriden the var accessibilityElements: [Any]? and used union to connect both elements. I've also assigned "Users" string to accessibilityLabel.
From user perspective this works as it should, VoiceOver reads Users and then user can select custom action which is named Edit.
Problem is that I don't know how can I fire this custom action from UITests. I know that XCUIElement contains array of UICustomActions and I can get its selector but then what?
I talked to Apple Engineers during WWDC19 Accessibility and Testing Labs and they said it is not possible right now. The reason why accessibility is not available during testing are security concerns. What they also said is that they don't use UITests for testing UIAccessibility and when creating accessibility elements support two cases - when there are UITests running and not.
I recommend making a suggestion using Feedback Assistant.
The purpose you're tring to reach isn't possible currently with iOS13 and Xcode 11.
The UITesting framework doesn't access the application code as unit tests do: you can't get an instance to perform selector + the array of custom actions is nil when in UITest ⇒ every custom action isn't reachable and then can't be fired at all.
XCUITEST works thanks to the accessibility properties like accessibilityIdentifier but isn't definitely designed to simply work for VoiceOver (inconceivable and incomprehensible in my view).
I hope that something new with UI testing will be introduced during the next WWDC for REAL accessibility testing.
For anyone else stuck on this, if you have a direct reference to the UIView in question, I've (well, a coworker of mine) found the following 'hack' to work quite well.
let view: UIView = YourViewWithCustomAction()
let customActionName: String = "<Your custom action name here>"
let action: UIAccessibilityCustomAction = view.accessibilityCustomActions!.first(where: { $0.name == customActionName })!
_ = action.target!.perform(action.selector, with: action)
As a disclaimer, this might only work when you have a custom UIView subclass that implements its own override var accessibilityElements.

Access elements in a custom view component in Swift 3 UI testing

I'm a newbie to any type of iOS programming. I am trying to write UI test cases for one of my scenes.
Following is the code I'm getting when I use recode method and tap on the custom component.
let button = XCUIApplication().children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .button).element
In this custom component there are two buttons. I wanna know which button is selected. For that I need to identify the button. But i'm getting same code where ever I tap on the custom view.
How can I access each component inside custom view. Any help would be great.
Add an accessibility identifier to your custom view in the app's code.
let customView: UIView!
customView.accessibilityIdentifier = "myCustomView"
Then access the contents like this:
let app = XCUIApplication()
let customView = app.otherElements["myCustomView"]
let button1 = customView.buttons.element(boundBy: 0)
let button2 = customView.buttons.element(boundBy: 1)
XCTAssertTrue(button1.isSelected)
XCTAssertFalse(button2.isSelected)
Note that to make your test deterministic, you should already know which button(s) should be selected. This ensures that your test tests the same thing every time it is run.
You need to make you elements visible to Accessibility.
I would suggest you to watch the WWDC Session about UI Testing in Xcode especially this part

iOS UITest - Navigate to all available screens

I am using iOS UITest for a Swift application. I use something like,
func testAllScreenNavigation() {
let app = XCUIApplication()
app.tabBars.buttons["Home"].tap()
app.navigationBars["Home"].buttons["More"].tap()
app.sheets.buttons["Cancel"].tap()
}
etc. to navigate some of the specific, tabs, buttons, etc. and switch to respective screens. But i want to navigate each and every screens of my Application (It can be BFS style navigation or DFS style navigation, no matter). Is there any way iOS provides so i can get all navigable elements and then explore deeper and deeper automatically for my App?
I also need to keep trace of which xcuoelement in a screen is already processed and which are not yet processed.
The only way I can think of is using Xcode UI test recorder feature.
While you are recording, navigate through all of your screens via the device/simulator and then the XCUIApplication() variable would be recorded with the appropriate references.
If the button/nav bar/any element has text on it, it will show up in the recorded code or else it will be referenced numerically.
Hope that helps.
Kind regards,
Mukund
I like your idea for getting all views and check whether the layouting and localization for example is fine.
I think you need to specify your criteria for "screens" and how they are accessed.
Basically, one could thing of the following structure
- UITabBarController
-- UISplitViewController
--- UINavigationController
---- UIViewController
----- UIBarButtonItems
----- UIView
----- UIButton
----- UISwitch
----- UITableViewCell
You could now go top down from the UITabBarController to the next controlling instance (might also skip one, e.g. SplitViewControllers on iPhones).
You can use the general property:
XCUIApplication().tabBars
Nevertheless that transition is the problem: How would you get from one ViewController to another and are they all position in the ViewController's View or do you have to loop the subviews of a view.
UIButton -> Touch Up Inside
UISwitch -> Value Changed
UITableViewCell -> DidSelectRowAtIndexPath
UIView -> UILongPressGestureRecognizer
This is how I would basically set it up:
For each UIViewController instance, get the related View (and perform the following call recursively).
Check all the subviews of a view.
For UIViews, go even further and check their subviews
For UIButtons, perform TouchUpInside
and so on.
Make sure to have a condition to stop going deeper, as UITableViews got a lot of subviews or your UIWebViews would of course be set up in a different way.
This way you should be able to navigate through a lot Views in your app hierarchy, but you will need some extensions for UIBarButtonItems, custom Gesture Recognizers and of course also for your "special" controls that might listen to value changes and perform a layout-change.
Accessing specific elements
In addition to the above approach where you simply get an array of elements of a specific type, you can access specific elements (e.g. those where you know they are of a very specific type with certain ValueChangeListeners or something)
To access a specific object in particular, like the TabBar example from above, you can use the accessibilityLabel like so. At first you need to declare the accessibilityLabel in your code or in the .xib-file/.storyboard:
// just to illustrate, so you get an idea:
self.tabBarController.isAccessibilityElement = true
self.tabBarController.accessibilityLabel = "tabBar"
And then do:
let tabBar = XCUIApplication().tabBars["tabBar"]
Here is Apple's documentation for setting these accessibilityLabels:
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html
A great way to get the related identifier of an element would be to use the Accessibility Inspector from Apple:
https://developer.apple.com/library/content/technotes/TestingAccessibilityOfiOSApps/TestAccessibilityiniOSSimulatorwithAccessibilityInspector/TestAccessibilityiniOSSimulatorwithAccessibilityInspector.html
Accessing elements in general
To access elements in general, you need to make use of the XCUIElementType of these objects, here you will access the objects based on their classes.
E.g. you could call:
"tabBars", "navBars", "tables", "buttons", and so on from the elements in general.
Still you would be facing the issue with "special controls". As the Apple documentation lacks (imho) some detail about properties and attributes, I do recommend the docs here: https://blog.metova.com/guide-xcode-ui-test/ It provides a great overview of what is accessible and may help you getting some better understanding.
An overview of the available XCUIElementTypes can be found here. Basically, the elementType property is an enumerated value that represents the type of an element. XCUIElementType is a very large enumeration and some of its members do not apply to iOS applications (they apply to MacOS X apps). Some of the more commonly used values are:
Alert
Button
NavigationBar
TabBar
ToolBar
ActivityIndicator
SegmentedControl
Picker
Image
StaticText
TextField
DatePicker
TextView
WebView
https://developer.apple.com/reference/xctest/xcuielementtype?language=objc

How to access variables within a subview of UITableViewCell contentView in iOS Swift Project

I am working on a Swift iOS app with a UITableView. I have used XCode Storyboard to add some labels to a prototype cell. I have also added a custom UIView class to the prototype cell. I can use viewWithTag to access the content of the labels, but I cannot access variables within my custom UIView. I need to pass in some integers so that the pie chart can be properly generated.
The class of my custom view is:
class protoBubbleView: UIView {
var necessaryInteger = 0
I have assigned it a tag of 9. I try to access it in this way:
let lbl : protoBubbleView = cell.viewWithTag(9)!
lbl.necessaryInteger = 5
But I receive errors indicating that viewWithTag only returns UIView and this cannot be assigned to lbl which is protoBubbleView.
How can I access the variables within this subview?
Thank you.
viewWithTag returns a regular UIView - you need to cast the returned value to protoBubbleView using the as? or as! operator, depending on what behaviour you prefer in case of a problem (i.e. when there is no view with that tag, or it is not a protoBubbleView)
For more details, see Downcasting
Add .contentView., as such
cell.contentView.viewWithTag(9)
Alternatively, I suggest using IBOutlets, ctrl-drag from your Storyboard into your Cell Subclass, and use cell.protoBubbleView.
Also, as Jacek said, use as!/? to make it a ProtoBubbleView to access its sub variables

How to Get the value(label) from the TextField inside the custom cell of a table View to post on te URL

I want my iOS app to pass to a URL the text the user types. The relevant code is pasted below. WHen I run the app, the text does not get assigned any value. It stays as null.
I am new to iOS programming and am probably missing something obvious here. Any help/pointers will be appreciated.
Mac OS version : 10.6.8 (64 bit)
Xcode version : 3.2.3
In the snapshop.. "I have created a Table View and placed custom cell inside each row of a table. TextField is inside the custom cell view. Post is a button next to the textField which is a done Button. If I click that button, the text we are entering in the textField should post on URL which i have specified in my code snippet."
NOTE: The text is like a comment and posting this comment that should post on particular image in that cell.
I have copied the code snippet below. I have also attached an image to explain.
-(IBAction)postAction:(id)sender
{
int index=[sender tag];
homecell *cell = [[homecell alloc] init];
UITextField *txt_c =(UITextField *)[cell.txt_comment viewWithTag:index];
NSLog(#"jj %#",txt_c);
gen_data *ut1=[[gen_data alloc]init];
gen_data *ut=[gen_data getInstance];
}
I assume that you have created that view using the interface builder, probably all you need is to connect that textfield as an IBOutlet and access the value.
IBOutlet is the key word here, search for it and you will find really fast the way to do it.
Check this link.
You should get some basics of iOS programming first.
Why are you creating a totally new custom cell that is irrelevant to your UITableView? When you create it that way, it's a totally new UITableViewCell.
You should connect it to it first, get its NSIndexPath and then operate with it and do what you want.
BTW, if you want to see the text of UITextfield you should NSLog myTextField.text
And you could easily write viewWithTag:sender.tag, no need to create an extra ivar here

Resources