2
0

Fixed MOC hierarchy, saving and permanent object ID resolution.

This commit is contained in:
Maarten Billemont 2014-04-15 00:26:13 -04:00
parent 11d1dc711d
commit 18657271ba
5 changed files with 45 additions and 36 deletions

View File

@ -77,12 +77,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
+ (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock { + (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock {
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady]; NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
if (!mainManagedObjectContext) if (!privateManagedObjectContextIfReady)
return NO; return NO;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext = mainManagedObjectContext; moc.parentContext = privateManagedObjectContextIfReady;
[moc performBlock:^{ [moc performBlock:^{
mocBlock( moc ); mocBlock( moc );
}]; }];
@ -92,12 +92,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock { + (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock {
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady]; NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
if (!mainManagedObjectContext) if (!privateManagedObjectContextIfReady)
return NO; return NO;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext = mainManagedObjectContext; moc.parentContext = privateManagedObjectContextIfReady;
[moc performBlockAndWait:^{ [moc performBlockAndWait:^{
mocBlock( moc ); mocBlock( moc );
}]; }];
@ -366,11 +366,18 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
if (self.saveObserver) if (self.saveObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver]; [[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
self.saveObserver = [[NSNotificationCenter defaultCenter] self.saveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification
addObserverForName:NSManagedObjectContextDidSaveNotification object:privateManagedObjectContext queue:nil usingBlock: object:privateManagedObjectContext queue:nil usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
[mainManagedObjectContext performBlock:^{ [mainManagedObjectContext performBlock:^{
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note]; [mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note];
NSError *error = nil;
if (![mainManagedObjectContext obtainPermanentIDsForObjects:
[mainManagedObjectContext.registeredObjects allObjects]
error:&error] || error)
err(@"Failed to obtain permanent object IDs for all objects in main context: %@", error);
}]; }];
}]; }];
@ -448,13 +455,13 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
newElement.version = element.version; newElement.version = element.version;
newElement.loginName = element.loginName; newElement.loginName = element.loginName;
[context deleteObject:element]; NSError *error = nil;
[context saveToStore];
NSError *error;
if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error]) if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error])
err(@"Failed to obtain a permanent object ID after changing object type: %@", error); err(@"Failed to obtain a permanent object ID after changing object type: %@", error);
[context deleteObject:element];
[context saveToStore];
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:element.objectID]; [[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:element.objectID];
element = newElement; element = newElement;
} }

View File

@ -48,13 +48,15 @@
- (void)setElement:(MPElementEntity *)element { - (void)setElement:(MPElementEntity *)element {
if ([_elementOID isEqual:element.objectID]) NSManagedObjectID *newElementOID = element.objectID;
NSAssert(!newElementOID.isTemporaryID, @"Element doesn't have a permanent objectID: %@", element);
if ([_elementOID isEqual:newElementOID])
return; return;
dbg(@"element: %@ -> %@", _elementOID, element.objectID); dbg(@"element: %@ -> %@", _elementOID, newElementOID);
_transientSite = nil; _transientSite = nil;
_elementOID = element.objectID; _elementOID = newElementOID;
[self updateAnimated:YES]; [self updateAnimated:YES];
[self reloadData]; [self reloadData];

View File

@ -69,8 +69,8 @@
[self.contentCollectionView reloadData]; [self.contentCollectionView reloadData];
NSIndexPath *visibleIndexPath = [self contentIndexPathForType: NSIndexPath *visibleIndexPath = [self contentIndexPathForType:
IfElse([[MPiOSAppDelegate get] activeUserForMainThread].defaultType, MPElementTypeGeneratedLong)]; IfElse([[MPiOSAppDelegate get] activeUserForMainThread].defaultType, MPElementTypeGeneratedLong)];
[self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath atScrollPosition:NO [self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath
animated:UICollectionViewScrollPositionCenteredHorizontally]; atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
} }
- (void)reloadWithElement:(MPElementEntity *)mainElement { - (void)reloadWithElement:(MPElementEntity *)mainElement {
@ -81,8 +81,8 @@
[self.contentCollectionView reloadData]; [self.contentCollectionView reloadData];
NSIndexPath *visibleIndexPath = [self contentIndexPathForType:mainElement.type]; NSIndexPath *visibleIndexPath = [self contentIndexPathForType:mainElement.type];
[self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath atScrollPosition:NO [self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath
animated:UICollectionViewScrollPositionCenteredHorizontally]; atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
} }
#pragma mark - UICollectionViewDataSource #pragma mark - UICollectionViewDataSource

View File

@ -295,8 +295,8 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) {
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.avatarCollectionView) { if (collectionView == self.avatarCollectionView) {
[self.avatarCollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally [self.avatarCollectionView scrollToItemAtIndexPath:indexPath
animated:YES]; atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
// Deselect all other cells. // Deselect all other cells.
for (NSUInteger otherItem = 0; otherItem < [collectionView numberOfItemsInSection:indexPath.section]; ++otherItem) for (NSUInteger otherItem = 0; otherItem < [collectionView numberOfItemsInSection:indexPath.section]; ++otherItem)

View File

@ -20,7 +20,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rWM-08-aab" userLabel="Users Root"> <view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rWM-08-aab" userLabel="Users Root">
<rect key="frame" x="0.0" y="0.0" width="321" height="504"/> <rect key="frame" x="0.0" y="0.0" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="VDd-oM-ZOO" userLabel="Store Activity"> <activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="VDd-oM-ZOO" userLabel="Store Activity">
@ -28,7 +28,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView> </activityIndicatorView>
<navigationBar contentMode="scaleToFill" misplaced="YES" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="790-G2-I8g"> <navigationBar contentMode="scaleToFill" misplaced="YES" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="790-G2-I8g">
<rect key="frame" x="0.0" y="20" width="321" height="44"/> <rect key="frame" x="0.0" y="20" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="barTintColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/> <color key="barTintColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<items> <items>
@ -36,7 +36,7 @@
</items> </items>
</navigationBar> </navigationBar>
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" alpha="0.0" contentMode="scaleToFill" misplaced="YES" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="L6J-pd-gcp" userLabel="Avatar Collection"> <collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" alpha="0.0" contentMode="scaleToFill" misplaced="YES" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="L6J-pd-gcp" userLabel="Avatar Collection">
<rect key="frame" x="0.0" y="20" width="321" height="484"/> <rect key="frame" x="0.0" y="20" width="320" height="484"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="ATB-kM-EGu"> <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="ATB-kM-EGu">
@ -147,7 +147,7 @@
</connections> </connections>
</button> </button>
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-gJ-NRE" userLabel="Next Avatar"> <button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-gJ-NRE" userLabel="Next Avatar">
<rect key="frame" x="277" y="127" width="44" height="53"/> <rect key="frame" x="276" y="127" width="44" height="53"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="44" id="oAm-YX-Fx5"/> <constraint firstAttribute="width" constant="44" id="oAm-YX-Fx5"/>
@ -161,23 +161,23 @@
</connections> </connections>
</button> </button>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qp1-nX-o4i" userLabel="Entry" customClass="PearlUIView"> <view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qp1-nX-o4i" userLabel="Entry" customClass="PearlUIView">
<rect key="frame" x="20" y="216" width="281" height="63"/> <rect key="frame" x="20" y="216" width="280" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Enter your full name:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="5fe-rt-zFa" userLabel="Entry Label"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Enter your full name:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="5fe-rt-zFa" userLabel="Entry Label">
<rect key="frame" x="20" y="0.0" width="241" height="18"/> <rect key="frame" x="20" y="0.0" width="240" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="17"/> <fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="ui_textfield.png" translatesAutoresizingMaskIntoConstraints="NO" id="UfK-na-vOU" userLabel="Field Background"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="ui_textfield.png" translatesAutoresizingMaskIntoConstraints="NO" id="UfK-na-vOU" userLabel="Field Background">
<rect key="frame" x="0.0" y="26" width="281" height="37"/> <rect key="frame" x="0.0" y="26" width="280" height="37"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<rect key="contentStretch" x="0.25" y="0.25" width="0.49999999999999961" height="0.49999999999999961"/> <rect key="contentStretch" x="0.25" y="0.25" width="0.49999999999999961" height="0.49999999999999961"/>
</imageView> </imageView>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" clearsOnBeginEditing="YES" minimumFontSize="14" translatesAutoresizingMaskIntoConstraints="NO" id="z3Z-AB-fG2" userLabel="Entry Field"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" clearsOnBeginEditing="YES" minimumFontSize="14" translatesAutoresizingMaskIntoConstraints="NO" id="z3Z-AB-fG2" userLabel="Entry Field">
<rect key="frame" x="10" y="30" width="261" height="29"/> <rect key="frame" x="10" y="30" width="260" height="29"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="28"/> <fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="28"/>
@ -187,23 +187,23 @@
</connections> </connections>
</textField> </textField>
<view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fdS-zb-K9I" userLabel="Entry Tip"> <view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fdS-zb-K9I" userLabel="Entry Tip">
<rect key="frame" x="28" y="-38" width="225" height="82"/> <rect key="frame" x="28" y="-38" width="224" height="82"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="g2g-5i-er4"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="g2g-5i-er4">
<rect key="frame" x="0.0" y="0.0" width="225" height="82"/> <rect key="frame" x="0.0" y="0.0" width="224" height="82"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.15000000000000002" y="0.14999999999999999" width="0.69999999999999973" height="0.44999999999999996"/> <rect key="contentStretch" x="0.15000000000000002" y="0.14999999999999999" width="0.69999999999999973" height="0.44999999999999996"/>
</imageView> </imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Looks like a typo!" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="ZI7-qg-7OW"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Looks like a typo!" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="ZI7-qg-7OW">
<rect key="frame" x="20" y="12" width="185" height="17"/> <rect key="frame" x="20" y="12" width="184" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/> <fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Try again; the password was wrong." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" preferredMaxLayoutWidth="185" translatesAutoresizingMaskIntoConstraints="NO" id="KhE-Yj-Kvm"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Try again; the password was wrong." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" preferredMaxLayoutWidth="185" translatesAutoresizingMaskIntoConstraints="NO" id="KhE-Yj-Kvm">
<rect key="frame" x="20" y="37" width="185" height="14"/> <rect key="frame" x="19" y="37" width="185" height="14"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
@ -248,7 +248,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</view> </view>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XEP-O3-ayG" userLabel="Footer" customClass="PearlUIView"> <view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XEP-O3-ayG" userLabel="Footer" customClass="PearlUIView">
<rect key="frame" x="0.0" y="391" width="321" height="113"/> <rect key="frame" x="0.0" y="403" width="320" height="101"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vHz-dw-oPb" userLabel="GitTip" customClass="LLGitTip"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vHz-dw-oPb" userLabel="GitTip" customClass="LLGitTip">
@ -288,7 +288,7 @@
</constraints> </constraints>
</view> </view>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" misplaced="YES" text="Press and hold to delete or reset user." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="N9g-Kk-yjc" userLabel="Hint"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.5" contentMode="left" misplaced="YES" text="Press and hold to delete or reset user." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="N9g-Kk-yjc" userLabel="Hint">
<rect key="frame" x="20" y="79" width="281" height="14"/> <rect key="frame" x="20" y="79" width="280" height="14"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/> <fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/>
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/> <color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
@ -304,7 +304,7 @@
<constraint firstItem="N9g-Kk-yjc" firstAttribute="leading" secondItem="XEP-O3-ayG" secondAttribute="leading" constant="20" symbolic="YES" id="fmq-PK-LJE"/> <constraint firstItem="N9g-Kk-yjc" firstAttribute="leading" secondItem="XEP-O3-ayG" secondAttribute="leading" constant="20" symbolic="YES" id="fmq-PK-LJE"/>
<constraint firstAttribute="centerX" secondItem="vHz-dw-oPb" secondAttribute="centerX" id="jxv-pr-0fu"/> <constraint firstAttribute="centerX" secondItem="vHz-dw-oPb" secondAttribute="centerX" id="jxv-pr-0fu"/>
<constraint firstAttribute="trailing" secondItem="N9g-Kk-yjc" secondAttribute="trailing" constant="20" symbolic="YES" id="mi6-gX-BNO"/> <constraint firstAttribute="trailing" secondItem="N9g-Kk-yjc" secondAttribute="trailing" constant="20" symbolic="YES" id="mi6-gX-BNO"/>
<constraint firstAttribute="bottom" secondItem="N9g-Kk-yjc" secondAttribute="bottom" constant="20" symbolic="YES" id="ybQ-hS-EaU"/> <constraint firstAttribute="bottom" secondItem="N9g-Kk-yjc" secondAttribute="bottom" constant="8" id="ybQ-hS-EaU"/>
</constraints> </constraints>
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/> <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/>