Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-23812] Hyperloop: UIColor type properties is not working with Xcode 8 beta

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2016-09-09T13:59:17.000+0000
Affected Version/sRelease 5.5.0
Fix Version/sRelease 5.5.0, hyperloop 1.2.7
ComponentsHyperloop, iOS, Tooling
Labelsqe-5.5.0
ReporterJosh Longton
AssigneeJan Vennemann
Created2016-08-23T23:35:05.000+0000
Updated2016-09-15T18:20:22.000+0000

Description

In Xcode 8 beta 6 on the build of the application the instance of redColor is generated but not the class.

Steps to reproduce:

Download the Xcode beta

Select to use the beta version of Xcode xcode-select -s <xcode beta location>

Create a new application with hyperloop

Use the app.js below in the application

appc run -p ios

Select to use the GA version of Xcode xcode-select -s <xcode GA location>

appc run -p ios

App.js

{noformat} var UIView = require('UIKit/UIView'), UIColor = require('UIKit/UIColor'), UIImage = require('UIKit/UIImage'), CGRectMake = require('CoreGraphics').CGRectMake; var win = Ti.UI.createWindow({ backgroundColor: 'white', layout: 'vertical' }); var view = UIView.alloc().initWithFrame(CGRectMake(10, 10, 50, 50)); view.backgroundColor = UIColor.redColor(); win.add(view); win.open(); {noformat}

Actual when using Xcode 8 beta 6

{noformat} [ERROR] Script Error { [ERROR] column = 40; [ERROR] line = 11; [ERROR] message = "UIColor.redColor is not a function. (In 'UIColor.redColor()', 'UIColor.redColor' is undefined)"; [ERROR] sourceURL = "file:///Users/Josh/Library/Developer/CoreSimulator/Devices/D5EEC5AB-078C-46AA-AC55-05BBBD410CB7/data/Containers/Bundle/Application/6680ADD3-DB71-4F72-8610-D837D5476666/Hyperloop%20forward%20testing.app/app.js"; [ERROR] } {noformat}

Expected

The application runs as it does in Xcode 7.3.1

Comments

  1. Josh Longton 2016-08-23

    I will investigate this issue to see if anything else have been affected in the Xcode beta.
  2. Jeff Haynie 2016-08-23

    I helped Josh trouble shoot. It looks like based on the HL code gen output that in the newer SDK UIColor redColor is now both +[UIColor redColor] and -[UIColor redColor] and the generation (JS) only generates the instance and not both the instance and the class methods.
  3. Hans Knöchel 2016-08-24

    Yep, Xcode 8 introduced the color-properties to (probably) ease the syntax on the Obj-C side - which also generates the property getter / class method.
       @property(class, nonatomic, readonly) UIColor *redColor; 
       
    They seem to use the also in Xcode 8 introduced UIKIT_DEFINE_AS_PROPERTIES statement to switch between the (class)-property and class-method usage. So in this case, the above statement seems to be true and so the usual class-methods as we know them are not even compiled by iOS. Bonus: The statement is defined as the following:
       #define UIKIT_DEFINE_AS_PROPERTIES (!defined(SWIFT_CLASS_EXTRA) || (defined(SWIFT_SDK_OVERLAY_UIKIT_EPOCH) && SWIFT_SDK_OVERLAY_UIKIT_EPOCH >= 1))
       
    So we may need to investigate if it makes sense to make it *a)* detect the define and property automcatically or *b)* stick to the "old" behavior for now.
  4. Jan Vennemann 2016-08-30

    So the main problem here is that Hyperloop does not differentiate between instance and class properties. As Jeff already pointed out, it recognizes the property but treats it as an instance property, thus resulting in wrong code generated in the JS files. I'll update the metabase generator and the templates to also support the new class level properties.
  5. Jan Vennemann 2016-08-31

    WIP PR: https://github.com/appcelerator/hyperloop.next/pull/65 Here is what i have so far, but now i've run into a bug in libclang (well, at least i think its a bug). As said before, the idea is to detect if a property is a class property and generate the matching js code in this case. We use clang_Cursor_getObjCPropertyAttributes to read the attributes defined on a property. The thing is, as soon as the property contains the class attribute this function will always return CXObjCPropertyAttr_noattr. Meaning we have no way to detect if a property is a class property or not. Any ideas how to workaround this are greatly appreciated :)
  6. Jan Vennemann 2016-09-01

    *sigh* Turns out the rpath build setting was hardcoded to the Xcode 7 toolchain directory and therefore loading the wrong version of libclang causing this unexpected behaviour. Changed it to use the currently selected Xcode version using $(DEVELOPER_DIR), works like a charm now. PR updated and ready for review, [~hansknoechel] PR: https://github.com/appcelerator/hyperloop.next/pull/65 PR (1.2.X): https://github.com/appcelerator/hyperloop.next/pull/66
  7. Hans Knöchel 2016-09-02

    Ok, so the PR works. However, we now cannot use the known syntax UIColor.redColor() anymore, only UIColor.redColor (property instead of method). I see this as a breaking change in Hyperloop, so we should be very cautious integrating is change. If possible, couldn't we "just" support both and generate a util-method that creates both the JS method and property? Thoughts?
  8. Jeff Haynie 2016-09-02

    we should support both class and instance properties. both are legal in JS
  9. Jan Vennemann 2016-09-05

    The PR does exactly that. I compared with the normal instance property UILabel.text today and this property works exactly the same. You can use label.text but not label.text(). As Hans said this is a breaking change in the UIColor api (and other classes that switched to class properties) on our side because of the way objc properties work. Through the property synthesize process in objc nothing changes as the getter/setter methods replace the removed class methods. In JS we can only either use the property or the method but not both. I'm currently looking into wether we could improve the usage detection so using UIColor.redColor() would cause the method to be generated and UIColor.redColor would trigger the property to be generated.
  10. Jan Vennemann 2016-09-07

    Ok, for now i updated the [1.2.X PR](https://github.com/appcelerator/hyperloop.next/pull/66) with a simple but not really elegant workaround to maintain api compatibility. We just check against a list of predefined properties (all that are new in iOS 10 because of the UIKIT_DEFINE_AS_PROPERTIES and FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8) macros) and generate the getter method rather than the property if it is in this list. I'm not really happy with this solution as we would have to maintain the list of properties if anything changes in future iOS SDKs (Script to detect properties affected by the macros: https://gist.github.com/janvennemann/380dde99ef9aa96c6d4a990bee520642). However, there is currently no other way to determine which properties are generated because of those two macros. Referring to my last comment, we could detect if someone uses UIColor.redColor() or UIColor.redColor and then either generate the appropriate method or property. Using the method and property simultaneously could result in a build error stating to use either of them but not both. The question is if we want to invest more time on this or just remove the workaround in a future version of Hyperloop and introduce the new api based on properties?
  11. Chee Kiat Ng 2016-09-08

    [~jvennemann] [~hansknoechel] Ok so I spoke with Ingo. We have agreed to go ahead with this PR for the sdk 5.5.0 release. And the proposal is to remove the workaround in Hyperloop 2.0.0 (Ti SDK 6.0.0) and introduce the new api based on properties. So let's get started on testing this PR asap and get a 1.2.7 up.
  12. Chee Kiat Ng 2016-09-08

    Did a simple FT. For this to work, if you have 2 Xcodes installed, please remember to sudo xcode-select --switch /Applications/Xcode-GM.app before doing a ./build.sh After you install the built module, if you do *appc run -p ios -I 10.0* on hyperloop-examples, it works flawlessly. However, if you do *appc run -p ios -I 9.3* on hyperloop-examples, it will fail with [ERROR] Unable to find Info.plist in root of specified app path: /Users/kiat/titaniumModules/hyperloop-examples/build/iphone/build/Products/Debug-iphonesimulator/Hyperloop_Sample.app/Info.plist And it's true, it's missing. weird! Here is why. Hyperloop metabase generation is entirely dependent on the pre-selected Xcode. It's not dependent on the -I 10.0 flag. Here are the rules for Hyperloop to work in the scenario where you have 2 Xcodes existing. 1. sudo xcode-select --switch /Applications/Xcode-GM.app followed by appc run -p ios -I 10.0 2. sudo xcode-select --switch /Applications/Xcode.app followed by appc run -p ios -I 9.3 If you mix up this combination, the build will fail with various types of errors, such as the missing info.plist. I am ok to put this in the release notes as "how to use hyperloop if you have 2 versions of Xcode installed" if we can't fix this in the short time we have. (considering QE still needs to test this)
  13. Hans Knöchel 2016-09-09

    PR approved & merged! [~jvennemann] Please file an own ticket for the bad-access crashes when using classes in a certain edge-case scenario. Thanks!
  14. Eric Wieber 2016-09-15

    Verified fixed, using: MacOS 10.12 (16A313a) Studio 4.7.1.201609100950 Ti SDK 5.5.0.GA Appc NPM 4.2.7 Appc CLI 5.5.0 Alloy 1.9.2 Xcode 8.0 (8A218a) UIColor type properties can be used via the UIColor.<color>Color() methods with Xcode 8 GA without error. Accessing the properties by actual instance properties UIColor.<color>Color fails, but that should be covered in Hyperloop 2.0.0, as Kiat mentioned above. Tested using the provided sample code as well as using the UIColor methods in other test apps.

JSON Source