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.
I am trying to move a swift file that I exported from PaintCode 2 into my project. I did the following.
Exported the project via PaintCode
Moved the file into Xcode
On my storyboard I put a UIView
Clicked on the newly created UIView and selected the class that I imported from PaintCode.
Now I am looking a white box:
Now the file I got from PaintCode was of type NSObject which I knew couldn't be right so I changed it to UImage. Still getting the same result.
---------UPDATE-----------
I created a new Cococa Class of type UIView, and did the following:
#IBDesignable
class CareerButtonClass: UIView {
//CareerButton.drawCanvas2()
func drawCareerButton() {
CareerButton.drawCanvas2()
}
}
Then I named the custom class on IUView in the storyboard CareerButtonClass.
Here are what my files look like:
Still getting the same result.
For those who run by this post I finally found a good example here:
PaintCode Tutorial for Developers (Swift 2.0): Getting Started
That's because PaintCode exports a class with a collection of methods that you can use to draw the content.
Depending on the methods you choose, it can either generate a UIImage for you or you can call the code to draw in the current context.
It's up to you to implement where to use those methods.
The class you got from PaintCode is NSObject and it’s right. StyleKit is a collection of all graphics you use in your app.
To render the button, you need to override drawRect method in your UIView. And call the method to draw the Career Button.
#IBDesignable
class CareerButtonClass: UIView {
override func drawRect(rect: CGRect) {
StyleKit.drawCareerButton()
}
}
See PaintCode FAQ #29.
I'm trying to make a framework of a custom UIViewController using #IBInspectable to edit its properties in Interface Builder.
public class BWWalkthroughPageViewController: UIViewController {
#IBInspectable public var speed: CGPoint = CGPointZero
#IBInspectable public var speedVariance: CGPoint = CGPointZero
#IBInspectable public var animationType: String = ""
#IBInspectable public var animateAlpha: Bool = false
}
If the framework source code is in a sample app project, the properties come up to Attribute Inspector as shown in the image below,
but if I add the built framework to my app project, the properties are not displayed in the inspector.
Is it possible to show the inspectable properties in a built framework to Interface Builder? If possible, how to?
Here is the framework source code, which is forked from a non-framework project.
https://github.com/yoichitgy/BWWalkthrough/tree/support-carthage
Creating framework
Create default framework and add there your swift files.
Then set your swift files as public.
After that copy your framework and add it to your project folder
Use the framework
Add the framework in your project
Create new viewController in your storyboard and set viewController's class which is located in your framework
Thats all. You will see your your properties in the storyboard.
The reason the attributes won't show up in Interface Builder in your app but do in your framework is because your framework isn't a target of your app. The easiest way to ensure that it is included is to use Cocoapods, it'll handle everything nicely for you and the setup is relatively easy.
A side note: IBDesignable and IBInspectable really don't have anything to do with each other. With IBInspectable, you can expose a limited amount of property types to Interface Builder or a Storyboard (things like NSNumber, Bool, UIColor, etc). IBDesignable however is used to live render your views in a nib or storyboard. They're very handy to use together i.e. changing properties for your inspectable attributes and seeing your view rendered.
I'm running Xcode 6.1 and I have been using IB_DESIGNABLE with IBInspectable for quite a few projects already but all of the sudden it just doesn't work anymore. I have created subclassed buttons that arrange the image and the title vertically centred above each other and enable the user to set a border width and color through IB with IBInspectable.
The following warning is logged and there is no preview available of my code in drawRect:
warning: IB Designables: Ignoring user defined runtime attribute for key path "spacingBetweenLabelAndImage" on instance of "UIButton". Hit an exception when attempting to set its value: [<UIButton 0x7f9278591260> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key spacingBetweenLabelAndImage.
Still, runtime it renders like I intended it to render and it also honours that same custom spacing I've added through IB.
Here's the code of the menubutton that rearranges the button and the title:
#import "HamburgerButton.h"
IB_DESIGNABLE
#interface HamburgerImageButton : HamburgerButton
#property IBInspectable CGFloat spacingBetweenLabelAndImage;
#end
Implementation:
#import "HamburgerImageButton.h"
#implementation HamburgerImageButton
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGSize imageSize = self.imageView.frame.size;
CGSize titleSize = self.titleLabel.frame.size;
// Move the label left and the image right by half the width
CGFloat leftInset = titleSize.width / 2;
CGFloat rightInset = imageSize.width / 2;
CGFloat halfSpacing = self.spacingBetweenLabelAndImage == 0 ? 0 : self.spacingBetweenLabelAndImage / 2;
CGFloat topInset = imageSize.height / 2 + halfSpacing;
CGFloat bottomInset = titleSize.height / 2 + halfSpacing;
UIEdgeInsets imageInsets = UIEdgeInsetsMake(-bottomInset, leftInset, bottomInset, -leftInset);
UIEdgeInsets titleInsets = UIEdgeInsetsMake(topInset, -rightInset, -topInset, rightInset);
self.imageEdgeInsets = imageInsets;
self.titleEdgeInsets = titleInsets;
}
#end
You've probably noticed it inherits HamburgerButton. This basic hamburger button does not have an image and it only draws the border around the button. This basic hamburger button has exactly the same problem: it does not draw it's border in drawRect in IB and it has the same type of errors. Here's that code for sake of completeness:
#import <UIKit/UIKit.h>
IB_DESIGNABLE
#interface HamburgerButton : UIButton
#property IBInspectable CGFloat borderWidth;
#property IBInspectable UIColor *borderColor;
#end
Implementation:
#import "HamburgerButton.h"
#import <QuartzCore/QuartzCore.h>
#implementation HamburgerButton
- (void)copyInspectables {
self.layer.borderWidth = self.borderWidth;
self.layer.borderColor = self.borderColor.CGColor;
}
- (void)drawRect:(CGRect)rect {
[self copyInspectables];
}
#end
I don't really understand why it just throws a warning and nothing else. I didn't really change what I did. I've checked the storyboard, it's iOS 7 and up, meant to run in Xcode 6 (latest).
It complains about not being able to find that value on UIButton and that's a bit weird because I've subclassed it.
Update:
So I changed everything around and it worked. Now it craps out again, without changing anything else. I think there's a bug in Xcode 6.1... :/
I have been working extensively with Live Views since it's introductions and like a lot of new features in Xcode initially, it has some flaws. Still I like it a lot and I hope that it will be improved in newer versions.
Cause:
Live Views work with #property properties that get a special IB_Designable tag that will give the UI class extra attributes it can approach via User Defined Runtime Attributes that will be set through the Attributes Inspector. You will see that all those properties also exist in the Identity Inspector. The root cause of the problem is that it cannot map those User Defined Runtime Attributes anymore to exposed properties.
As soon as you open up a Storyboard or xib that uses IB_Designable, Xcode will recompile the screen at every change if you have "Automatically Refresh Views" turned on. Since your code influences your UI as well this doesn't have to be a change in Interface Builder per se.
With simpler projects on faster machines this works pretty well the majority of the time. With larger projects that also have more IB_Designable the CPU simply doesn't have enough capacity to keep up with you and you will get a sort of time-out error while rendering the UI. This is the cause of the "warning: IB Designables: Ignoring user defined runtime attribute for key path "spacingBetweenLabelAndImage" on instance of "UIButton". Hit an exception when attempting to set its value: [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key spacingBetweenLabelAndImage." error.
It will also not update your UI anymore with your custom code. This is not a problem when you run it though, because at run time it will reflect those changes.
Another cause can be that your code simply doesn't compile when it tries to compile in the background. This is inevitable when you are working on code so that triggers it frequently as well.
Solution:
We need to make sure that your custom view class compiles again so the properties can be set successfully via Interface Builder
While in a storyboard, go to "Editor" in the top bar menu
deselect "Automatically refresh views" if it was still turned on
Close all your storyboard tabs
Rebuild the project
Fix all build errors if any
Re-open your storyboard.
Go to "Editor" again and click "Refresh All Views"
The warnings should be gone and if it worked before you will see your custom view code again as well.
After a comment below by sunkas: it's always a very good idea to clean your solution thoroughly in case of any weird problems that persist.
How I personally fixed this:
In the identity inspector in User Defined Runtime Attributes I noticed that I had an old IB_Inspectable element that I had deleted from my code, but it was still in there. Removing it with the - button got rid of this error.
Try changing your "CGFloat" declaration for spacingBetweenLabelAndImage into "NSNumber".
As far as I know, you can't call "setValue:" on a C-type variable.
Changing the declaration of "spacingBetwenLabelAndImage" to NSNumber would also require you to change a bit of code too:
CGFloat halfSpacing = self.spacingBetweenLabelAndImage == 0 ? 0 : self.spacingBetweenLabelAndImage / 2;
might become something like:
CGFloat halfSpacing = (self.spacingBetweenLabelAndImage ? ([self.spacingBetweenLabelAndImage floatValue] / 2) : 0.0);
(I'm not 100% certain if this is a perfect translation of the first line, but I wanted to show how to get a floatValue out of a NSNumber)
I had a similar problem, but I actually removed the property from the class and Interface Builder was still complaining about the missing property, tough.
Tried many things, like cleaning, rebuilding... But nothing worked!
What really solved was right clicking in the Storyboard file, selecting "Open As" and then "Source code". This opened the storyboard XML content in the editor and I was able to look for references to the missing property until I found the section:
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute... keyPath="My Missing Property Name">
...
</userDefinedRuntimeAttributes>
After removing the whole section, I saved the file and refreshed the view in Interface Builder. Now all warnings are gone!
I used the method Departamento B provided but it didn't really work. However, I fixed my problem by
1. Selecting the buggy views from story board
2. Clicking (Editor - Debug selected view)
Hope this helps
If you are sure that you set all the setters right, and if you imported some other SDKs in your project and you are getting this issue,
check 'Linked Frameworks and Libraries' in Target - General.
After I correctly linked some SDK frameworks, the error went away.
I had this error, when has two targets. One with my main project and other with target, where i hold designable classes (for faster build).
The issue was that in storyboard there were missing a Module.
I have the following set of code:
CustomView.h
#import <UIKit/UIKit.h>
IB_DESIGNABLE
#interface CustomView : UIView
#property (nonatomic) IBInspectable UIColor *borderColor;
#property (nonatomic) IBInspectable CGFloat borderWidth;
#property (nonatomic) IBInspectable CGFloat cornerRadius;
#end
CustomView.m
#import "CustomView.h"
#implementation CustomView
- (void)setBorderColor:(UIColor *)borderColor {
_borderColor = borderColor;
self.layer.borderColor = borderColor.CGColor;
}
- (void)setBorderWidth:(CGFloat)borderWidth {
_borderWidth = borderWidth;
self.layer.borderWidth = borderWidth;
}
- (void)setCornerRadius:(CGFloat)cornerRadius {
_cornerRadius = cornerRadius;
self.layer.cornerRadius = cornerRadius;
}
#end
(For Swift reference, this problem was also occurring with Swift code)
CustomView.swift
#IBDesignable
class CustomView : UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
#IBInspectable var borderColor : UIColor = UIColor.clearColor() {
didSet {
self.layer.borderColor = borderColor.CGColor
}
}
#IBInspectable var borderWidth : CGFloat = 0.0 {
didSet {
self.layer.borderWidth = borderWidth
}
}
#IBInspectable var cornerRadius : CGFloat = 0.0 {
didSet {
self.layer.cornerRadius = cornerRadius
}
}
}
I added a UIView to a view controller on the storyboard and set its subclass to CustomView.
This adds the "Designables" row. It is stuck on "Updating" and the tooltip says "Waiting for Target to Build". It never changes from this status.
When I move to the attributes inspect, I am able to set these IBInspectable properties:
And once set, they also show up in the "User Defined Runtime Attributes":
However, the "Designables" status never moves beyond "Updating" with still the same tooltip (I've tried Cmd+B building several times, nothing changes).
Moreover, as I set the IBInspectable properties, I get a warning for each one:
IBDesignables - Ignoring user defined runtime attribute for key path "borderColor" on instance of "UIView" ... this class is not key-value coding-compliant for the key borderColor.
Screenshot of the warnings generated:
I am familiar with the key-value coding-compliant issues and generally know how to solve them... but I don't understand how to solve this issue here. According to the view's identity inspector, the view is a "CustomView" (not a regular "UIView", which doesn't have these properties). And if the view weren't a "CustomView" then these designable properties wouldn't show up in the Attributes Inspector, right? But when Interface Builder tries to apply these attributes to the view, it goes back to thinking the view's class is "UIView" and cannot apply the attributes.
Any help? Please let me know if I've left out some important detail, but for what it's worth, I followed this tutorial exactly (other than ObjC vs Swift). It's also worth noting that I followed this tutorial exactly on another machine and it worked like a charm (I intended to make this post last night but the computer I was on then didn't have this issue).
Based on comments, it has been suggest that perhaps the .m file isn't included and that might be causing the problem. I thought surely I would have gone out of my way for this scenario to be the case, but I checked anyway.
When I first started attempting to do this, I was under the understanding that the IB_DESIGNABLE classes had to be part of a different UIKit framework. So from this first screenshot, you can see that I set up a "CustomViews" framework, which has one class, CustomView. You'll also see here that I also created a OtherView, which is identical to CustomView, except it's not in a separate framework. The identical problem persists on the storyboard between both classes however.
Here we have a screenshot indicating that CustomView.m is included to be built with the CustomViews framework:
Meanwhile, the following screenshot indicates several things:
CustomViews.framework is appropriately included in the main project.
OtherView.m is also included as a compile source, so even if something is wrong with CustomView, OtherView should work, however it generates identical errors.
Main.storyboard and LaunchScreen.xib are showing up as red. I have no idea why, and haven't the slightest clue as to why LaunchScreen.xib should (I haven't touched this file), though I can say after looking at other projects, Main.storyboard also shows up in red for those projects, and I'm not doing anything with IB_DESIGNABLE or IBInspectable there.
I have tried and retried this several times now. It works every time on my computer at home--I can not reproduce the problem described in this question at home. At work, it never works. The problem described in this question happens every time.
Both computers are Mac Minis purchased new this year (not the new models, late 2012 model). Both computers are running OS X Yosemite 10.10. Both computers are running Xcode Version 6.1. At home, the build is (6A1052d). This morning, I can confirm that both computers are running identical builds of Xcode.
Others have suggested to me that it might be bad RAM. That seems far fetched to me. I've restarted the project multiple times, restarted the computer multiple times. Seems to me if there were bad RAM on a computer approximately 6 months old, that I'd be seeing other problems, and that this problem would be less consistent. But this exact problem persists despite numerous times restarting the entire project from scratch and full restarts on the computer.
It should be worth noting that if I actually compile and run this project, the custom view with the IBInspectable properties actually displays as I expect the storyboard to display it. I imagine that this would be the case even with out the IB_DESIGNABLE and IBInspectable directives however, as these are created as User Defined Runtime Attributes.
Based on chrisco's suggestion to debug the selected view (which I had already done, but went to try again for good measure), I noticed a couple of other options at the bottom of the Editor menu.
Automatically Refresh Views
Refresh All Views
I clicked "Refresh All Views" and after Xcode had a bit of a think, suddenly the storyboard was displaying my view as expected (properly applying my IBInspectable properties).
I then went through the whole process again to confirm that this is the solution.
I created a new class, ThirdView. This class is identical to the others, again. I changed my view's class to ThirdView and got something slightly different this time:
Clicking "Show" to me to the warnings:
A new one this time:
Using class UIView for object with custom class because the class ThirdView does not exist.
This isn't really any more helpful than what already existed. Plus, now the other three warnings have doubled into 6 strangely.
Anyway, if I click "Refresh All Views" from the Editor drop down menu again, all the errors go away, and once again, the view properly displays.
Still, up to this point, everything I did was stuff I never messed with at home. At home, it just worked. So I turned on "Automatically Refresh Views" and created a "FourthView" to test--once again, identical to the first three.
After changing the view's class to "FourthView" the designables label said "Updating" for a short moment then finally said "Up to date":
So, I checked my computer at home. "Automatically Refresh Views" is turned on at the computer that was always working. It was turned off at the computer that wasn't. I don't ever remember touching this menu option. I can't even tell you for sure whether it existed before Xcode 6. But this option is what was making the difference.
TL;DR, if you're having the same problem described in the question, make sure "Automatically Refresh Views" is turned on (or manually "Refresh All Views" when you need an update in IB):
Just a quick hint for anyone else having this problem: remember to specify the type of the variable.
// Doesn't show up in IB
#IBInspectable var includeLeftSection = true
// Shows now that it knows the type
#IBInspectable var includeLeftSection : Bool = true
I have a few more details that may cause your IBDesignable classes to not be loaded.
Select your problematic storyboard/xib where your custom views ought to display.
In the navigator area, head to the Report Navigator in your XCode workspace/project.
In the Editor menu of XCode, hit (as mentioned by nhgrif), the "Refresh All Views" option. This will cause IB to launch a compile for a whole bunch of stuff that you, I'm certain, would not expect.
In the Report Navigator, Click on "By Group" to filter content and look at the "Interface Builder" section. You will see that for the sake of loading the custom IBDesignable views framework, it will compile LOTS of things. If any of these targets do NOT compile, such as (perhaps deprecated) unit test targets (even if they are totally unrelated to the code that loads these views or storyboard), then IB will fail at loading your dll.
In my case, IB tried to compile 8 targets, including 4 that where unit tests that had not been updated since recent refactoring changes we've been working on.
Most of the code changes/fixes I have done in order for IB to properly load and display my customs views where not related or even linked against these classes, nor would it ever load the storyboard in the course of running these unit tests. Yet, IB had a dependency on the whole workspace compiling for it to work.
I had the same warning Ignoring user defined runtime attribute for key path .. even though I am absolutely sure I didn't do anything wrong with my custom IBDesignable view class.
Turned out, in my case, it got to do with Xcode cache.
rm -rf ~/Library/Developer/Xcode/DerivedData/*
Purge DerivedData and the warning is gone.
Incase any one else comes up against the error IB Designables class does not exist, for the same reason as I did. Top answer was not my issue... but here is a slightly related problem...
There is a property hidden in the story board source code called customModule.
For example I had a class called ForwardArrow inside a separate framework that I accidentally added to my main target.
So the XML for some views ended up as
customClass="ForwardArrow" customModule="MainTargetNameWasHere"
When I removed them from the main target in the build the story board did not update MainTargetNameWasHere to CustomViews which is the framework where it was located and started giving that no class found error.
So TLDR; Make sure that if your IBDesignable is in another framework that the customModule xml attribute in your story board is set to the right value. And if it isn't there at all add it.
Example from my source:
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MUG-jc-2Ml" customClass="ForwardArrow" customModule="CustomViews">
As my example, I was using CheckboxButton via pod and the graphics of checkbox never shows up in the storyboard while I got the same issues described in the question here:
warning: IB Designables: Using class UIView for object with custom class because the class CheckboxButton does not exist
and
warning: IB Designables: Ignoring user defined runtime attribute for key path "checkColor" on instance of "UIView". Hit an exception when attempting to set its value: [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key checkColor.
The way solved my problem was to supply the module with name CheckboxButton as below:
Note: you should replace CheckboxButton to whatever the name of module you are using.
I personally solved this problem by using the "-" button to delete content from my identity inspector. When you remove custom classes, change content in the IB and then add a new custom class, the designable elements in the identity inspector don't get removed and it caused me to have that error. Just Delete everything and rebuild.
I know this is answered, but here is one more experience.
I was having some problems unrelated to this issue, but in the process I removed #IBInspectable from the vars in my class and deleted the attributes from the identity inspector (alt-apple-3).
After fixing the (code) issue with the component, I refreshed everything a ton of times, but still no attributes in the identity inspector.
Eventually, I noticed that they were back, but only in the attributes inspector (alt-apple-4). As soon as I added values to them there, they re-appeared in the identity inspector
Dave Thomas's answer above gave me the (reverse) solution when not of the others (Derived Data, Editor > Refresh) did, but for the sake of clarity in case people aren't sure where to edit the XML... you don't need to!
In your storyboard file select the troublesome view
On the right-hand sidebar select the Identity Inspector tab (3rd option from the left).
You'll have your custom class, which should already be set, and the Module. For me this was empty, and I was getting the same errors as OP. I set the Module to my project name and BAM - it started working after rebuilding!
I just went through the ringer on this problem. I tried all the things listed here and elsewhere without any luck. This is a storyboard that worked fine forever and it suddenly stopped working with the "Ignoring user-defined runtime attribute..." problem.
For whatever reason, removing this code from one of my IBDesignable's fixed it:
-(void)viewDidLoad {
self.clipsToBounds = YES;
}
removing this caused all the warnings to go away, even in other IBDesignable objects. I have no idea why this one step fixed it, but maybe it will help someone else too.
I was having the same problem and I had to change the cornerRadius and BorderWidth to be a String and then cast it to CGFloat, it was the only solution for me to be able to change the values and see the changes in interface builder.
#IBInspectable var borderColor: UIColor? {
didSet {
layer.borderColor = borderColor!.CGColor
}
}
#IBInspectable var borderWidth: String? {
didSet {
layer.borderWidth = CGFloat(Int(borderWidth!) ?? 0)
}
}
#IBInspectable var cornerRadius: String? {
didSet {
layer.cornerRadius = CGFloat(Int(cornerRadius!) ?? 0)
layer.masksToBounds = layer.cornerRadius > 0
}
}