mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix iOS embedder memory management and other analyzer warnings (flutter/engine#29623)
This commit is contained in:
parent
e4aec6397c
commit
bcce079911
@ -10,7 +10,7 @@
|
||||
+ (instancetype)sharedInstance {
|
||||
static id _sharedInstance = nil;
|
||||
if (!_sharedInstance) {
|
||||
_sharedInstance = [FlutterBinaryCodec new];
|
||||
_sharedInstance = [[FlutterBinaryCodec alloc] init];
|
||||
}
|
||||
return _sharedInstance;
|
||||
}
|
||||
@ -29,7 +29,7 @@
|
||||
+ (instancetype)sharedInstance {
|
||||
static id _sharedInstance = nil;
|
||||
if (!_sharedInstance) {
|
||||
_sharedInstance = [FlutterStringCodec new];
|
||||
_sharedInstance = [[FlutterStringCodec alloc] init];
|
||||
}
|
||||
return _sharedInstance;
|
||||
}
|
||||
@ -54,7 +54,7 @@
|
||||
+ (instancetype)sharedInstance {
|
||||
static id _sharedInstance = nil;
|
||||
if (!_sharedInstance) {
|
||||
_sharedInstance = [FlutterJSONMessageCodec new];
|
||||
_sharedInstance = [[FlutterJSONMessageCodec alloc] init];
|
||||
}
|
||||
return _sharedInstance;
|
||||
}
|
||||
@ -109,7 +109,7 @@
|
||||
+ (instancetype)sharedInstance {
|
||||
static id _sharedInstance = nil;
|
||||
if (!_sharedInstance) {
|
||||
_sharedInstance = [FlutterJSONMethodCodec new];
|
||||
_sharedInstance = [[FlutterJSONMethodCodec alloc] init];
|
||||
}
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
@ -18,15 +18,15 @@ FLUTTER_DARWIN_EXPORT
|
||||
/**
|
||||
* The name of the callback.
|
||||
*/
|
||||
@property(retain) NSString* callbackName;
|
||||
@property(copy) NSString* callbackName;
|
||||
/**
|
||||
* The class name of the callback.
|
||||
*/
|
||||
@property(retain) NSString* callbackClassName;
|
||||
@property(copy) NSString* callbackClassName;
|
||||
/**
|
||||
* The library path of the callback.
|
||||
*/
|
||||
@property(retain) NSString* callbackLibraryPath;
|
||||
@property(copy) NSString* callbackLibraryPath;
|
||||
@end
|
||||
|
||||
/**
|
||||
|
||||
@ -34,6 +34,7 @@ static NSString* const kRestorationStateAppModificationKey = @"mod-date";
|
||||
- (void)dealloc {
|
||||
[_lifeCycleDelegate release];
|
||||
[_rootFlutterViewControllerGetter release];
|
||||
[_window release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@ -121,6 +121,22 @@ FLUTTER_ASSERT_ARC
|
||||
arguments:@"/custom/route#fragment"]);
|
||||
}
|
||||
|
||||
- (void)testReleasesWindowOnDealloc {
|
||||
__weak UIWindow* weakWindow;
|
||||
@autoreleasepool {
|
||||
id mockWindow = OCMClassMock([UIWindow class]);
|
||||
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
|
||||
appDelegate.window = mockWindow;
|
||||
weakWindow = mockWindow;
|
||||
XCTAssertNotNil(weakWindow);
|
||||
[mockWindow stopMocking];
|
||||
mockWindow = nil;
|
||||
appDelegate = nil;
|
||||
}
|
||||
// App delegate has released the window.
|
||||
XCTAssertNil(weakWindow);
|
||||
}
|
||||
|
||||
#pragma mark - Deep linking
|
||||
|
||||
- (void)testUniversalLinkPushRoute {
|
||||
|
||||
@ -7,6 +7,14 @@
|
||||
#include "flutter/lib/ui/plugins/callback_cache.h"
|
||||
|
||||
@implementation FlutterCallbackInformation
|
||||
|
||||
- (void)dealloc {
|
||||
[_callbackName release];
|
||||
[_callbackClassName release];
|
||||
[_callbackLibraryPath release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FlutterCallbackCache
|
||||
|
||||
@ -273,7 +273,7 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle) {
|
||||
if (exceptionDomains == nil) {
|
||||
return @"";
|
||||
}
|
||||
NSMutableArray* networkConfigArray = [[NSMutableArray alloc] init];
|
||||
NSMutableArray* networkConfigArray = [[[NSMutableArray alloc] init] autorelease];
|
||||
for (NSString* domain in exceptionDomains) {
|
||||
NSDictionary* domainConfiguration = [exceptionDomains objectForKey:domain];
|
||||
// Default value is false.
|
||||
@ -288,7 +288,7 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle) {
|
||||
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:networkConfigArray
|
||||
options:0
|
||||
error:NULL];
|
||||
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
return [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease];
|
||||
}
|
||||
|
||||
+ (bool)allowsArbitraryLoads:(NSDictionary*)appTransportSecurity {
|
||||
|
||||
@ -349,7 +349,7 @@ void HandleResponse(bool handled, void* user_data);
|
||||
*
|
||||
* Set by the initializer.
|
||||
*/
|
||||
@property(nonatomic) FlutterSendKeyEvent sendEvent;
|
||||
@property(nonatomic, copy, readonly) FlutterSendKeyEvent sendEvent;
|
||||
|
||||
/**
|
||||
* A map of pressed keys.
|
||||
@ -357,7 +357,7 @@ void HandleResponse(bool handled, void* user_data);
|
||||
* The keys of the dictionary are physical keys, while the values are the logical keys
|
||||
* of the key down event.
|
||||
*/
|
||||
@property(nonatomic) NSMutableDictionary<NSNumber*, NSNumber*>* pressingRecords;
|
||||
@property(nonatomic, retain, readonly) NSMutableDictionary<NSNumber*, NSNumber*>* pressingRecords;
|
||||
|
||||
/**
|
||||
* A constant mask for NSEvent.modifierFlags that Flutter synchronizes with.
|
||||
@ -396,7 +396,8 @@ void HandleResponse(bool handled, void* user_data);
|
||||
* Its values are |responseId|s, and keys are the callback that was received
|
||||
* along with the event.
|
||||
*/
|
||||
@property(nonatomic) NSMutableDictionary<NSNumber*, FlutterAsyncKeyCallback>* pendingResponses;
|
||||
@property(nonatomic, retain, readonly)
|
||||
NSMutableDictionary<NSNumber*, FlutterAsyncKeyCallback>* pendingResponses;
|
||||
|
||||
/**
|
||||
* Compare the last modifier flags and the current, and dispatch synthesized
|
||||
|
||||
@ -215,6 +215,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
[_registrars release];
|
||||
_binaryMessenger.parent = nil;
|
||||
[_binaryMessenger release];
|
||||
[_isolateId release];
|
||||
|
||||
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
||||
if (_flutterViewControllerWillDeallocObserver) {
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
|
||||
@interface FlutterEngineGroup ()
|
||||
@property(nonatomic, copy) NSString* name;
|
||||
@property(nonatomic, strong) NSMutableArray<NSValue*>* engines;
|
||||
@property(nonatomic, strong) FlutterDartProject* project;
|
||||
@property(nonatomic, retain) NSMutableArray<NSValue*>* engines;
|
||||
@property(nonatomic, retain) FlutterDartProject* project;
|
||||
@end
|
||||
|
||||
@implementation FlutterEngineGroup {
|
||||
@ -18,9 +18,9 @@
|
||||
- (instancetype)initWithName:(NSString*)name project:(nullable FlutterDartProject*)project {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.name = name;
|
||||
self.engines = [[NSMutableArray<NSValue*> alloc] init];
|
||||
self.project = project;
|
||||
_name = [name copy];
|
||||
_engines = [[NSMutableArray<NSValue*> alloc] init];
|
||||
_project = [project retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -30,6 +30,7 @@
|
||||
[center removeObserver:self];
|
||||
[_name release];
|
||||
[_engines release];
|
||||
[_project release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@ -42,4 +42,18 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertNotNil(spawnee);
|
||||
}
|
||||
|
||||
- (void)testReleasesProjectOnDealloc {
|
||||
__weak FlutterDartProject* weakProject;
|
||||
@autoreleasepool {
|
||||
FlutterDartProject* mockProject = OCMClassMock([FlutterDartProject class]);
|
||||
FlutterEngineGroup* group = [[FlutterEngineGroup alloc] initWithName:@"foo"
|
||||
project:mockProject];
|
||||
weakProject = mockProject;
|
||||
XCTAssertNotNil(weakProject);
|
||||
group = nil;
|
||||
mockProject = nil;
|
||||
}
|
||||
XCTAssertNil(weakProject);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -13,12 +13,14 @@ static constexpr CFTimeInterval kDistantFuture = 1.0e10;
|
||||
/**
|
||||
* The primary responders added by addPrimaryResponder.
|
||||
*/
|
||||
@property(nonatomic) NSMutableArray<id<FlutterKeyPrimaryResponder>>* primaryResponders;
|
||||
@property(nonatomic, retain, readonly)
|
||||
NSMutableArray<id<FlutterKeyPrimaryResponder>>* primaryResponders;
|
||||
|
||||
/**
|
||||
* The secondary responders added by addSecondaryResponder.
|
||||
*/
|
||||
@property(nonatomic) NSMutableArray<id<FlutterKeySecondaryResponder>>* secondaryResponders;
|
||||
@property(nonatomic, retain, readonly)
|
||||
NSMutableArray<id<FlutterKeySecondaryResponder>>* secondaryResponders;
|
||||
|
||||
- (void)dispatchToSecondaryResponders:(nonnull FlutterUIPressProxy*)press
|
||||
complete:(nonnull KeyEventCompleteCallback)callback
|
||||
@ -88,7 +90,7 @@ static constexpr CFTimeInterval kDistantFuture = 1.0e10;
|
||||
NSAssert([_primaryResponders count] >= 0, @"At least one primary responder must be added.");
|
||||
|
||||
__block auto weakSelf = [self getWeakPtr];
|
||||
__block int unreplied = [_primaryResponders count];
|
||||
__block NSUInteger unreplied = [self.primaryResponders count];
|
||||
__block BOOL anyHandled = false;
|
||||
FlutterAsyncKeyCallback replyCallback = ^(BOOL handled) {
|
||||
unreplied--;
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
@property(nonatomic, readonly) NSURL* url;
|
||||
@property(nonatomic, retain, readonly) NSURL* url;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -206,8 +206,8 @@ static void DNSSD_API registrationCallback(DNSServiceRef sdRef,
|
||||
// uri comes in as something like 'http://127.0.0.1:XXXXX/' where XXXXX is the port
|
||||
// number.
|
||||
if (weak) {
|
||||
NSURL* url =
|
||||
[[NSURL alloc] initWithString:[NSString stringWithUTF8String:uri.c_str()]];
|
||||
NSURL* url = [[[NSURL alloc]
|
||||
initWithString:[NSString stringWithUTF8String:uri.c_str()]] autorelease];
|
||||
weak.get().url = url;
|
||||
if (weak.get().enableObservatoryPublication) {
|
||||
[[weak.get() delegate] publishServiceProtocolPort:url];
|
||||
|
||||
@ -84,7 +84,7 @@ void ResetAnchor(CALayer* layer) {
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if ([super initWithFrame:frame]) {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.backgroundColor = UIColor.clearColor;
|
||||
}
|
||||
return self;
|
||||
|
||||
@ -650,7 +650,7 @@ static BOOL isScribbleAvailable() {
|
||||
// currently only support UITextFields, and password saving only supports
|
||||
// UITextFields and UITextViews, as of iOS 13.5.
|
||||
@interface FlutterSecureTextInputView : FlutterTextInputView
|
||||
@property(nonatomic, strong, readonly) UITextField* textField;
|
||||
@property(nonatomic, retain, readonly) UITextField* textField;
|
||||
@end
|
||||
|
||||
@implementation FlutterSecureTextInputView {
|
||||
@ -693,7 +693,7 @@ static BOOL isScribbleAvailable() {
|
||||
@property(nonatomic, assign) CGRect markedRect;
|
||||
@property(nonatomic) BOOL isVisibleToAutofill;
|
||||
@property(nonatomic, assign) BOOL accessibilityEnabled;
|
||||
@property(nonatomic, strong) UITextInteraction* textInteraction API_AVAILABLE(ios(13.0));
|
||||
@property(nonatomic, retain) UITextInteraction* textInteraction API_AVAILABLE(ios(13.0));
|
||||
|
||||
- (void)setEditableTransform:(NSArray*)matrix;
|
||||
@end
|
||||
@ -872,6 +872,9 @@ static BOOL isScribbleAvailable() {
|
||||
[_autofillId release];
|
||||
[_inputViewController release];
|
||||
[_selectionRects release];
|
||||
[_markedTextStyle release];
|
||||
[_textContentType release];
|
||||
[_textInteraction release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@ -957,8 +960,8 @@ static BOOL isScribbleAvailable() {
|
||||
}
|
||||
|
||||
- (NSRange)clampSelection:(NSRange)range forText:(NSString*)text {
|
||||
int start = MIN(MAX(range.location, 0), text.length);
|
||||
int length = MIN(range.length, text.length - start);
|
||||
NSUInteger start = MIN(MAX(range.location, 0), text.length);
|
||||
NSUInteger length = MIN(range.length, text.length - start);
|
||||
return NSMakeRange(start, length);
|
||||
}
|
||||
|
||||
@ -1118,8 +1121,8 @@ static BOOL isScribbleAvailable() {
|
||||
NSRange textRange = ((FlutterTextRange*)range).range;
|
||||
NSAssert(textRange.location != NSNotFound, @"Expected a valid text range.");
|
||||
// Sanitize the range to prevent going out of bounds.
|
||||
int location = MIN(textRange.location, self.text.length);
|
||||
int length = MIN(self.text.length - location, textRange.length);
|
||||
NSUInteger location = MIN(textRange.location, self.text.length);
|
||||
NSUInteger length = MIN(self.text.length - location, textRange.length);
|
||||
NSRange safeRange = NSMakeRange(location, length);
|
||||
return [self.text substringWithRange:safeRange];
|
||||
}
|
||||
@ -1918,8 +1921,8 @@ static BOOL isScribbleAvailable() {
|
||||
// The current password-autofillable input fields that have yet to be saved.
|
||||
@property(nonatomic, readonly)
|
||||
NSMutableDictionary<NSString*, FlutterTextInputView*>* autofillContext;
|
||||
@property(nonatomic, strong) FlutterTextInputView* activeView;
|
||||
@property(nonatomic, strong) FlutterTextInputViewAccessibilityHider* inputHider;
|
||||
@property(nonatomic, retain) FlutterTextInputView* activeView;
|
||||
@property(nonatomic, retain) FlutterTextInputViewAccessibilityHider* inputHider;
|
||||
@property(nonatomic, readonly) id<FlutterViewResponder> viewResponder;
|
||||
@end
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// FLUTTER_NOLINT: https://github.com/flutter/flutter/issues/93360
|
||||
|
||||
// The only point of this file is to ensure that the Flutter framework umbrella header can be
|
||||
// cleanly imported from an Objective-C translation unit. The target that uses this file copies the
|
||||
// headers to a path that simulates how users would actually import the framework outside of the
|
||||
|
||||
@ -73,7 +73,7 @@ typedef struct MouseState {
|
||||
* Keyboard animation properties
|
||||
*/
|
||||
@property(nonatomic, assign) double targetViewInsetBottom;
|
||||
@property(nonatomic, strong) CADisplayLink* displayLink;
|
||||
@property(nonatomic, retain) CADisplayLink* displayLink;
|
||||
|
||||
/**
|
||||
* Creates and registers plugins used by this view controller.
|
||||
@ -671,21 +671,24 @@ static void sendFakeTouchEvent(FlutterEngine* engine,
|
||||
}
|
||||
|
||||
- (void)addInternalPlugins {
|
||||
[self.keyboardManager release];
|
||||
self.keyboardManager = [[FlutterKeyboardManager alloc] init];
|
||||
self.keyboardManager = [[[FlutterKeyboardManager alloc] init] autorelease];
|
||||
fml::WeakPtr<FlutterViewController> weakSelf = [self getWeakPtr];
|
||||
FlutterSendKeyEvent sendEvent =
|
||||
^(const FlutterKeyEvent& event, FlutterKeyEventCallback callback, void* userData) {
|
||||
[_engine.get() sendKeyEvent:event callback:callback userData:userData];
|
||||
[weakSelf.get()->_engine.get() sendKeyEvent:event callback:callback userData:userData];
|
||||
};
|
||||
[self.keyboardManager
|
||||
addPrimaryResponder:[[FlutterEmbedderKeyResponder alloc] initWithSendEvent:sendEvent]];
|
||||
[self.keyboardManager addPrimaryResponder:[[FlutterChannelKeyResponder alloc]
|
||||
initWithChannel:self.engine.keyEventChannel]];
|
||||
[self.keyboardManager addSecondaryResponder:self.engine.textInputPlugin];
|
||||
FlutterChannelKeyResponder* responder = [[[FlutterChannelKeyResponder alloc]
|
||||
initWithChannel:self.engine.keyEventChannel] autorelease];
|
||||
[self.keyboardManager addPrimaryResponder:responder];
|
||||
FlutterTextInputPlugin* textInputPlugin = self.engine.textInputPlugin;
|
||||
if (textInputPlugin != nil) {
|
||||
[self.keyboardManager addSecondaryResponder:textInputPlugin];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeInternalPlugins {
|
||||
[self.keyboardManager release];
|
||||
self.keyboardManager = nil;
|
||||
}
|
||||
|
||||
@ -790,6 +793,8 @@ static void sendFakeTouchEvent(FlutterEngine* engine,
|
||||
|
||||
[self removeInternalPlugins];
|
||||
[self deregisterNotifications];
|
||||
|
||||
[_displayLink release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@ -1733,6 +1738,7 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
|
||||
- (void)encodeRestorableStateWithCoder:(NSCoder*)coder {
|
||||
NSData* restorationData = [[_engine.get() restorationPlugin] restorationData];
|
||||
[coder encodeDataObject:restorationData];
|
||||
[super encodeRestorableStateWithCoder:coder];
|
||||
}
|
||||
|
||||
- (void)decodeRestorableStateWithCoder:(NSCoder*)coder {
|
||||
|
||||
@ -760,6 +760,21 @@ typedef enum UIAccessibilityContrast : NSInteger {
|
||||
[self waitForExpectations:@[ expectation ] timeout:1.0];
|
||||
}
|
||||
|
||||
- (void)testReleasesKeyboardManagerOnDealloc {
|
||||
__weak FlutterKeyboardManager* weakKeyboardManager = nil;
|
||||
@autoreleasepool {
|
||||
FlutterViewController* viewController = [[FlutterViewController alloc] init];
|
||||
|
||||
[viewController addInternalPlugins];
|
||||
weakKeyboardManager = viewController.keyboardManager;
|
||||
XCTAssertNotNil(weakKeyboardManager);
|
||||
[viewController deregisterNotifications];
|
||||
viewController = nil;
|
||||
}
|
||||
// View controller has released the keyboard manager.
|
||||
XCTAssertNil(weakKeyboardManager);
|
||||
}
|
||||
|
||||
- (void)testDoesntLoadViewInInit {
|
||||
FlutterDartProject* project = [[FlutterDartProject alloc] init];
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
|
||||
|
||||
@ -31,7 +31,7 @@ extern NSNotificationName const FlutterViewControllerShowHomeIndicator;
|
||||
|
||||
@property(nonatomic, readonly) BOOL isPresentingViewController;
|
||||
@property(nonatomic, readonly) BOOL isVoiceOverRunning;
|
||||
@property(nonatomic) FlutterKeyboardManager* keyboardManager;
|
||||
@property(nonatomic, retain) FlutterKeyboardManager* keyboardManager;
|
||||
- (fml::WeakPtr<FlutterViewController>)getWeakPtr;
|
||||
- (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController;
|
||||
- (FlutterRestorationPlugin*)restorationPlugin;
|
||||
|
||||
@ -146,7 +146,7 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
@end // FlutterSwitchSemanticsObject
|
||||
|
||||
@interface FlutterScrollableSemanticsObject ()
|
||||
@property(nonatomic, strong) FlutterSemanticsScrollView* scrollView;
|
||||
@property(nonatomic, retain) FlutterSemanticsScrollView* scrollView;
|
||||
@end
|
||||
|
||||
@implementation FlutterScrollableSemanticsObject {
|
||||
@ -409,7 +409,7 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
withAttributes:
|
||||
(const flutter::StringAttributes&)attributes {
|
||||
NSMutableAttributedString* attributedString =
|
||||
[[NSMutableAttributedString alloc] initWithString:string];
|
||||
[[[NSMutableAttributedString alloc] initWithString:string] autorelease];
|
||||
for (const auto& attribute : attributes) {
|
||||
NSRange range = NSMakeRange(attribute->start, attribute->end - attribute->start);
|
||||
switch (attribute->type) {
|
||||
@ -749,7 +749,7 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) {
|
||||
@end
|
||||
|
||||
@interface FlutterPlatformViewSemanticsContainer ()
|
||||
@property(nonatomic, strong) UIView* platformView;
|
||||
@property(nonatomic, retain) UIView* platformView;
|
||||
@end
|
||||
|
||||
@implementation FlutterPlatformViewSemanticsContainer
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
@interface FlutterInactiveTextInput : UIView <UITextInput>
|
||||
|
||||
@property(nonatomic, copy) NSString* text;
|
||||
@property(nonatomic, readonly) NSMutableString* markedText;
|
||||
@property(readwrite, copy) UITextRange* selectedTextRange;
|
||||
@property(nonatomic, strong) UITextRange* markedTextRange;
|
||||
@property(nonatomic, copy) NSDictionary* markedTextStyle;
|
||||
@property(nonatomic, copy, readonly) NSMutableString* markedText;
|
||||
@property(copy) UITextRange* selectedTextRange;
|
||||
@property(nonatomic, strong, readonly) UITextRange* markedTextRange;
|
||||
@property(nonatomic, copy) NSDictionary<NSAttributedStringKey, id>* markedTextStyle;
|
||||
@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate;
|
||||
|
||||
@end
|
||||
|
||||
@ -16,8 +16,13 @@ static const UIAccessibilityTraits UIAccessibilityTraitUndocumentedEmptyLine = 0
|
||||
@synthesize beginningOfDocument = _beginningOfDocument;
|
||||
@synthesize endOfDocument = _endOfDocument;
|
||||
|
||||
- (instancetype)init {
|
||||
return [super init];
|
||||
- (void)dealloc {
|
||||
[_text release];
|
||||
[_markedText release];
|
||||
[_markedTextRange release];
|
||||
[_selectedTextRange release];
|
||||
[_markedTextStyle release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL)hasText {
|
||||
|
||||
@ -22,6 +22,7 @@ bool ShouldUseMetalRenderer() {
|
||||
if (@available(iOS METAL_IOS_VERSION_BASELINE, *)) {
|
||||
auto device = MTLCreateSystemDefaultDevice();
|
||||
ios_version_supports_metal = [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v3];
|
||||
[device release];
|
||||
}
|
||||
return ios_version_supports_metal;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user