Skip to content

[ASPrimitiveTraitCollection] Always treat preferredContentSize as a potential nil #trivial - #757

Merged
nguyenhuy merged 3 commits into
TextureGroup:masterfrom
ypogribnyi:safeAreaInsets-fix
Mar 21, 2018
Merged

nguyenhuy merged 3 commits into
TextureGroup:masterfrom
ypogribnyi:safeAreaInsets-fix

Conversation

@ypogribnyi

Copy link
Copy Markdown
Contributor

As ASPrimitiveTraitCollection is a struct, the application can always initialize it in its own way, without using Texture-provided initialization functions. This may lead to preferredContentSize field being nil, which, in turn, may lead to frustrating crashes when the struct is given to Texture.

While simply advising the user to always use the provided initialization functions should solve the problem, it's better to always treat this structure as possibly improperly initialized and guard against nil value in this field.

Additionally this PR explicitly marks all UIContentSizeCategory usage in ASTraitCollection class as non-null.

Add nil-value checks for preferredContentSizeCategory.
@ay8s

ay8s commented Jan 19, 2018

Copy link
Copy Markdown
Collaborator

It seems better now when changing device orientation @ypogribnyi. Is there documentation around initializing ASPrimitiveTraitCollection? Might be missing something.

We were seeing this on iOS 10 & 11.

@ypogribnyi

Copy link
Copy Markdown
Contributor Author

The preferred way to create ASPrimitiveTraitCollection is to use ASPrimitiveTraitCollectionMakeDefault() or ASPrimitiveTraitCollectionFromUITraitCollection(UITraitCollection*). There wasn't any documentation about this, but I added a comment to ASPrimitiveTraitCollection definition in this PR (not sure if that's enough).

By the way, why do we expose two trait collections interfaces (ASPrimitiveTraitCollection and ASTraitCollection) to the user? Might it be better to hide one of them?

@nguyenhuy

Copy link
Copy Markdown
Member

By the way, why do we expose two trait collections interfaces (ASPrimitiveTraitCollection and ASTraitCollection) to the user? Might it be better to hide one of them?

Good questions! Based on facebookarchive/AsyncDisplayKit#1592, I think the original reason is to have ASTraitCollection as a friendly object-based API and ASPrimitiveTraitCollection as the internal actual struct that is used throughout the framework. We should at least document this reasoning, and/or move ASPrimitiveTraitCollection to a framework-private interface.

@nguyenhuy nguyenhuy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ypogribnyi Great reasoning on the possibility that ASPrimitiveTraitCollection may be initialized manually, and defend against such case.

@ay8s This PR should mitigate your crash, although I'd suggest to dig a bit deeper into your codebase and fix the root cause (initialize ASPrimitiveTraitCollection using the provided functions or better yet, switch to ASTraitCollection). Let us know what you find!

Comment thread Source/Details/ASTraitCollection.h Outdated
#endif

@property (nonatomic, assign, readonly) UIContentSizeCategory preferredContentSizeCategory;
@property (nonatomic, assign, readonly) UIContentSizeCategory _Nonnull preferredContentSizeCategory;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need _Nonnull annotations since we already use NS_ASSUME_NONNULL_BEGIN at the beginning of this file (here). It's always good to be defensive and guard against unexpected values in the implementation though.

} else {
return AS_UIContentSizeCategoryUnspecified();
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, feel free to ignore this: It's a bit shorter to use ternary operator here, i.e:

return sizeCategory ? sizeCategory : AS_UIContentSizeCategoryUnspecified();

Comment thread Source/Details/ASTraitCollection.m Outdated
.userInterfaceIdiom = UIUserInterfaceIdiomUnspecified,
.layoutDirection = UITraitEnvironmentLayoutDirectionUnspecified,
.preferredContentSizeCategory = ASPrimitiveContentSizeCategoryMake(AS_UIContentSizeCategoryUnspecified()),
.preferredContentSizeCategory = AS_UIContentSizeCategoryUnspecified(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we remove the ASPrimitiveContentSizeCategoryMake in here. If you read the comment above ASPrimitiveContentSizeCategory we have to use ASPrimitiveContentSizeCategoryMake

* Mark [ASViewController overrideDisplayTraitsWithWindowSize] as deprecated.

Code review changes:
* Remove unneeded nonnull annotations
* Add null check in ASTraitCollection constructor implementation
* Codestyle
* Add some documentation about ASPrimitiveTraitCollection vs ASTraitCollection usage
@ay8s

ay8s commented Jan 23, 2018

Copy link
Copy Markdown
Collaborator

Thanks @ypogribnyi. We don't actually initialize either ASPrimitiveCollectionTraits or ASTraitCollection ourselves.

I wonder if this might help with digging into the cause http://crashes.to/s/058c9ea3e54

@ypogribnyi

Copy link
Copy Markdown
Contributor Author

@ay8s, thank you for your input! I finally managed to reproduce the crash. Looks like it occurs in ASViewControllers that are used without a node (i.e. not using -[ASViewController initWithNode:]). Could you please confirm if that is your case?

I'm reproducing it on master in ASDKgrams UIKit tab. It crashes after device rotation when trying to log the trait collection fetched with

ASPrimitiveTraitCollection traitCollection = _node.primitiveTraitCollection;

while having nil in _node.

Although having a nil node in a view controller is perfectly valid and fully documented behaviour, I didn't expect that at all.

Anyways, this PR should fix the problem.

@ay8s

ay8s commented Jan 26, 2018

Copy link
Copy Markdown
Collaborator

Yup that'd be it! Thanks @ypogribnyi!

Comment thread Source/Details/ASTraitCollection.m Outdated
}
}

ASDISPLAYNODE_INLINE ASPrimitiveContentSizeCategory safePrimitiveContentSizeCategory(ASPrimitiveContentSizeCategory sizeCategory) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still should prefix this functions with AS

Comment thread Source/Details/ASTraitCollection.m Outdated
.userInterfaceIdiom = UIUserInterfaceIdiomUnspecified,
.layoutDirection = UITraitEnvironmentLayoutDirectionUnspecified,
.preferredContentSizeCategory = ASPrimitiveContentSizeCategoryMake(AS_UIContentSizeCategoryUnspecified()),
.preferredContentSizeCategory = AS_UIContentSizeCategoryUnspecified(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we remove the ASPrimitiveContentSizeCategoryMake in here. If you read the comment above ASPrimitiveContentSizeCategory we have to use ASPrimitiveContentSizeCategoryMake

Comment thread Source/Details/ASTraitCollection.m Outdated

ASDISPLAYNODE_INLINE ASPrimitiveContentSizeCategory safePrimitiveContentSizeCategory(ASPrimitiveContentSizeCategory sizeCategory) {
return sizeCategory ? sizeCategory : AS_UIContentSizeCategoryUnspecified();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in both cases we have to use ASPrimitiveContentSizeCategoryMake(AS_UIContentSizeCategoryUnspecified())

Remove safePrimitiveContentSizeCategory in favour of AS_safeContentSizeCategory.

@nguyenhuy nguyenhuy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for dropping the ball here, @ypogribnyi. LGTM now. Thanks!

@nguyenhuy
nguyenhuy merged commit e954b10 into TextureGroup:master Mar 21, 2018
bernieperez pushed a commit to AtomTickets/Texture that referenced this pull request Apr 25, 2018
…otential nil #trivial (TextureGroup#757)

* Fix ASPrimitiveTraitCollection initialization on iOS 9.
Add nil-value checks for preferredContentSizeCategory.

* * Mark -[ASTraitCollection init] as deprecated.
* Mark [ASViewController overrideDisplayTraitsWithWindowSize] as deprecated.

Code review changes:
* Remove unneeded nonnull annotations
* Add null check in ASTraitCollection constructor implementation
* Codestyle
* Add some documentation about ASPrimitiveTraitCollection vs ASTraitCollection usage

* Rename safeContentSizeCategory to AS_safeContentSizeCategory.

Remove safePrimitiveContentSizeCategory in favour of AS_safeContentSizeCategory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants