Skip to content

Commit

Permalink
Merge pull request #1838 from sparkle-project/fix-delta-updates
Browse files Browse the repository at this point in the history
Fix delta updates edge cases
  • Loading branch information
zorgiepoo authored Apr 26, 2021
2 parents 478cc98 + 063974c commit 84cdb0c
Show file tree
Hide file tree
Showing 18 changed files with 120 additions and 98 deletions.
6 changes: 3 additions & 3 deletions Sparkle/SPUAutomaticUpdateDriver.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ - (void)resumeUpdate:(id<SPUResumableUpdate>)__unused resumableUpdate completion
SULog(SULogLevelError, @"Error: resumeDownloadedUpdate:completion: called on SPUAutomaticUpdateDriver");
}

- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate
- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate
{
self.updateItem = updateItem;

if (updateItem.isInformationOnlyUpdate || preventsAutoupdate) {
[self.coreDriver deferInformationalUpdate:updateItem preventsAutoupdate:preventsAutoupdate];
[self.coreDriver deferInformationalUpdate:updateItem secondaryUpdate:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate];
[self abortUpdate];
} else {
[self.coreDriver downloadUpdateFromAppcastItem:updateItem inBackground:YES];
[self.coreDriver downloadUpdateFromAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem inBackground:YES];
}
}

Expand Down
4 changes: 1 addition & 3 deletions Sparkle/SPUBasicUpdateDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN

@protocol SPUBasicUpdateDriverDelegate <NSObject>

- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)appcastItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain;
- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)appcastItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain;

- (void)basicDriverIsRequestingAbortUpdateWithError:(nullable NSError *)error;

Expand All @@ -38,8 +38,6 @@ NS_ASSUME_NONNULL_BEGIN

- (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpdateDriverCompletion)completionBlock;

@property (nullable, nonatomic, readonly) SUAppcastItem *nonDeltaUpdateItem;

- (void)abortUpdateAndShowNextUpdateImmediately:(BOOL)shouldSignalShowingUpdate resumableUpdate:(id<SPUResumableUpdate> _Nullable)resumableUpdate error:(nullable NSError *)error;

@end
Expand Down
21 changes: 8 additions & 13 deletions Sparkle/SPUBasicUpdateDriver.m
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ - (void)checkForUpdatesAtAppcastURL:(NSURL *)appcastURL withUserAgent:(NSString
}
}

- (void)notifyResumableUpdateItem:(SUAppcastItem *)updateItem systemDomain:(NSNumber * _Nullable)systemDomain
- (void)notifyResumableUpdateItem:(SUAppcastItem *)updateItem secondaryUpdateItem:(SUAppcastItem *)secondaryUpdateItem systemDomain:(NSNumber * _Nullable)systemDomain
{
if (updateItem == nil) {
[self.delegate basicDriverIsRequestingAbortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUResumeAppcastError userInfo:@{ NSLocalizedDescriptionKey: SULocalizedString(@"Failed to resume installing update.", nil) }]];
Expand All @@ -88,7 +88,7 @@ - (void)notifyResumableUpdateItem:(SUAppcastItem *)updateItem systemDomain:(NSNu
[self notifyFinishLoadingAppcast];

SUAppcastItem *nonNullUpdateItem = updateItem;
[self notifyFoundValidUpdateWithAppcastItem:nonNullUpdateItem preventsAutoupdate:NO systemDomain:systemDomain];
[self notifyFoundValidUpdateWithAppcastItem:nonNullUpdateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:NO systemDomain:systemDomain];
}
}

Expand All @@ -100,7 +100,7 @@ - (void)resumeInstallingUpdateWithCompletion:(SPUUpdateDriverCompletion)completi
assert(hostBundleIdentifier != nil);
[SPUProbeInstallStatus probeInstallerUpdateItemForHostBundleIdentifier:hostBundleIdentifier completion:^(SPUInstallationInfo * _Nullable installationInfo) {
dispatch_async(dispatch_get_main_queue(), ^{
[self notifyResumableUpdateItem:installationInfo.appcastItem systemDomain:@(installationInfo.systemDomain)];
[self notifyResumableUpdateItem:installationInfo.appcastItem secondaryUpdateItem:nil systemDomain:@(installationInfo.systemDomain)];
});
}];
}
Expand All @@ -109,12 +109,7 @@ - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpda
{
self.completionBlock = completionBlock;

[self notifyResumableUpdateItem:resumableUpdate.updateItem systemDomain:nil];
}

- (SUAppcastItem *)nonDeltaUpdateItem
{
return self.appcastDriver.nonDeltaUpdateItem;
[self notifyResumableUpdateItem:resumableUpdate.updateItem secondaryUpdateItem:resumableUpdate.secondaryUpdateItem systemDomain:nil];
}

- (void)didFailToFetchAppcastWithError:(NSError *)error
Expand Down Expand Up @@ -142,7 +137,7 @@ - (void)didFinishLoadingAppcast:(SUAppcast *)appcast
}
}

- (void)notifyFoundValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain
- (void)notifyFoundValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain
{
if (!self.aborted) {
[[NSNotificationCenter defaultCenter] postNotificationName:SUUpdaterDidFindValidUpdateNotification
Expand All @@ -153,13 +148,13 @@ - (void)notifyFoundValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem preven
[self.updaterDelegate updater:self.updater didFindValidUpdate:updateItem];
}

[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate systemDomain:systemDomain];
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate systemDomain:systemDomain];
}
}

- (void)didFindValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate
- (void)didFindValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate
{
[self notifyFoundValidUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate systemDomain:nil];
[self notifyFoundValidUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryAppcastItem preventsAutoupdate:preventsAutoupdate systemDomain:nil];
}

- (void)didNotFindUpdateWithLatestAppcastItem:(nullable SUAppcastItem *)latestAppcastItem hostToLatestAppcastItemComparisonResult:(NSComparisonResult)hostToLatestAppcastItemComparisonResult
Expand Down
6 changes: 3 additions & 3 deletions Sparkle/SPUCoreBasedUpdateDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN

@protocol SPUCoreBasedUpdateDriverDelegate <NSObject>

- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate;
- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate;

- (void)installerDidFinishPreparationAndWillInstallImmediately:(BOOL)willInstallImmediately silently:(BOOL)willInstallSilently;

Expand Down Expand Up @@ -61,9 +61,9 @@ NS_ASSUME_NONNULL_BEGIN

- (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpdateDriverCompletion)completionBlock;

- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem inBackground:(BOOL)background;
- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryUpdateItem inBackground:(BOOL)background;

- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate;
- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem secondaryUpdate:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate;

- (void)extractDownloadedUpdate;

Expand Down
29 changes: 17 additions & 12 deletions Sparkle/SPUCoreBasedUpdateDriver.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ @interface SPUCoreBasedUpdateDriver () <SPUBasicUpdateDriverDelegate, SPUDownloa
@property (nonatomic, readonly) SPUInstallerDriver *installerDriver;
@property (nonatomic, weak, readonly) id<SPUCoreBasedUpdateDriverDelegate> delegate;
@property (nonatomic) SUAppcastItem *updateItem;
@property (nonatomic) SUAppcastItem *secondaryUpdateItem;
@property (nonatomic) id<SPUResumableUpdate> resumableUpdate;
@property (nonatomic) SPUDownloadedUpdate *downloadedUpdateForRemoval;

Expand All @@ -53,6 +54,7 @@ @implementation SPUCoreBasedUpdateDriver
@synthesize installerDriver = _installerDriver;
@synthesize delegate = _delegate;
@synthesize updateItem = _updateItem;
@synthesize secondaryUpdateItem = _secondaryUpdateItem;
@synthesize host = _host;
@synthesize resumingInstallingUpdate = _resumingInstallingUpdate;
@synthesize silentInstall = _silentInstall;
Expand Down Expand Up @@ -147,33 +149,34 @@ - (void)basicDriverDidFinishLoadingAppcast
}
}

- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain
- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain
{
self.updateItem = updateItem;
self.secondaryUpdateItem = secondaryUpdateItem;

if (self.resumingInstallingUpdate) {
assert(systemDomain != nil);
[self.installerDriver resumeInstallingUpdateWithUpdateItem:updateItem systemDomain:systemDomain.boolValue];
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate];
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate];
} else {
if (!self.preventsInstallerInteraction) {
// Simple case - delegate allows interaction, so we should continue along
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate];
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate];
} else {
// Package type installations will always require installer interaction as long as we don't support running as root
// If it's not a package type installation, we should be okay since we did an auth check before checking for updates above
if (![updateItem.installationType isEqualToString:SPUInstallationTypeApplication]) {
[self.delegate coreDriverIsRequestingAbortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUNotAllowedInteractionError userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"A new update is available but cannot be installed because interaction has been prevented."] }]];
} else {
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate];
[self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate];
}
}
}
}

- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem inBackground:(BOOL)background
- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryUpdateItem inBackground:(BOOL)background
{
self.downloadDriver = [[SPUDownloadDriver alloc] initWithUpdateItem:updateItem host:self.host userAgent:self.userAgent httpHeaders:self.httpHeaders inBackground:background delegate:self];
self.downloadDriver = [[SPUDownloadDriver alloc] initWithUpdateItem:updateItem secondaryUpdateItem:secondaryUpdateItem host:self.host userAgent:self.userAgent httpHeaders:self.httpHeaders inBackground:background delegate:self];

if ([self.updaterDelegate respondsToSelector:@selector((updater:willDownloadUpdate:withRequest:))]) {
[self.updaterDelegate updater:self.updater
Expand Down Expand Up @@ -222,9 +225,9 @@ - (void)downloadDriverDidDownloadUpdate:(SPUDownloadedUpdate *)downloadedUpdate
[self extractUpdate:downloadedUpdate];
}

- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate
- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem secondaryUpdate:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate
{
self.resumableUpdate = [[SPUInformationalUpdate alloc] initWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate];
self.resumableUpdate = [[SPUInformationalUpdate alloc] initWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate];
}

- (void)extractDownloadedUpdate
Expand Down Expand Up @@ -381,16 +384,18 @@ - (void)basicDriverIsRequestingAbortUpdateWithError:(nullable NSError *)error

- (void)installerDidFailToApplyDeltaUpdate
{
SUAppcastItem *nonDeltaUpdateItem = self.basicDriver.nonDeltaUpdateItem;
assert(nonDeltaUpdateItem != nil);
SUAppcastItem *secondaryUpdateItem = self.secondaryUpdateItem;
assert(secondaryUpdateItem != nil);

BOOL backgroundDownload = self.downloadDriver.inBackground;

[self clearDownloadedUpdate];

// Fall back to the non-delta update. Note that we don't want to trigger another update was found event.
self.updateItem = nonDeltaUpdateItem;
[self downloadUpdateFromAppcastItem:nonDeltaUpdateItem inBackground:backgroundDownload];
self.updateItem = secondaryUpdateItem;
self.secondaryUpdateItem = nil;

[self downloadUpdateFromAppcastItem:secondaryUpdateItem secondaryAppcastItem:nil inBackground:backgroundDownload];
}

- (void)abortUpdateAndShowNextUpdateImmediately:(BOOL)shouldShowUpdateImmediately error:(nullable NSError *)error
Expand Down
2 changes: 1 addition & 1 deletion Sparkle/SPUDownloadDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface SPUDownloadDriver : NSObject

- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate;
- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem secondaryUpdateItem:(SUAppcastItem * _Nullable)secondaryUpdateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate;

- (instancetype)initWithHost:(SUHost *)host;

Expand Down
7 changes: 5 additions & 2 deletions Sparkle/SPUDownloadDriver.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ @interface SPUDownloadDriver () <SPUDownloaderDelegate>
@property (nonatomic) id<SPUDownloaderProtocol> downloader;
@property (nonatomic) NSXPCConnection *connection;
@property (nonatomic, readonly) SUAppcastItem *updateItem;
@property (nonatomic, readonly) SUAppcastItem *secondaryUpdateItem;
@property (nonatomic, readonly) SUHost *host;
@property (nonatomic, copy) NSString *temporaryDirectory;
@property (nonatomic, copy) NSString *downloadName;
Expand All @@ -43,6 +44,7 @@ @implementation SPUDownloadDriver
@synthesize downloader = _downloader;
@synthesize connection = _connection;
@synthesize updateItem = _updateItem;
@synthesize secondaryUpdateItem = _secondaryUpdateItem;
@synthesize request = _request;
@synthesize inBackground = _inBackground;
@synthesize host = _host;
Expand Down Expand Up @@ -106,11 +108,12 @@ - (instancetype)initWithHost:(SUHost *)host
return self;
}

- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate
- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem secondaryUpdateItem:(SUAppcastItem * _Nullable)secondaryUpdateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate
{
self = [self initWithHost:host];
if (self != nil) {
_updateItem = updateItem;
_secondaryUpdateItem = secondaryUpdateItem;
_delegate = delegate;

_inBackground = background;
Expand Down Expand Up @@ -188,7 +191,7 @@ - (void)downloaderDidFinishWithTemporaryDownloadData:(SPUDownloadData * _Nullabl
SULog(SULogLevelError, @"Warning: Downloader's expected content length (%llu) != Appcast item's length (%llu)", self.expectedContentLength, self.updateItem.contentLength);
}

SPUDownloadedUpdate *downloadedUpdate = [[SPUDownloadedUpdate alloc] initWithAppcastItem:self.updateItem downloadName:self.downloadName temporaryDirectory:self.temporaryDirectory];
SPUDownloadedUpdate *downloadedUpdate = [[SPUDownloadedUpdate alloc] initWithAppcastItem:self.updateItem secondaryAppcastItem:self.secondaryUpdateItem downloadName:self.downloadName temporaryDirectory:self.temporaryDirectory];

[self.delegate downloadDriverDidDownloadUpdate:downloadedUpdate];
});
Expand Down
2 changes: 1 addition & 1 deletion Sparkle/SPUDownloadedUpdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface SPUDownloadedUpdate : NSObject <SPUResumableUpdate>

- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory;
- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory;

@property (nonatomic, copy, readonly) NSString *downloadName;
@property (nonatomic, copy, readonly) NSString *temporaryDirectory;
Expand Down
4 changes: 3 additions & 1 deletion Sparkle/SPUDownloadedUpdate.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ @implementation SPUDownloadedUpdate
// If we ever enable auto-synthesize in the future, we'll still need this synthesize
// because the property is declared in a protocol
@synthesize updateItem = _updateItem;
@synthesize secondaryUpdateItem = _secondaryUpdateItem;

@synthesize downloadName = _downloadName;
@synthesize temporaryDirectory = _temporaryDirectory;

- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory
- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryUpdateItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory
{
self = [super init];
if (self != nil) {
_updateItem = updateItem;
_secondaryUpdateItem = secondaryUpdateItem;
_downloadName = [downloadName copy];
_temporaryDirectory = [temporaryDirectory copy];
}
Expand Down
2 changes: 1 addition & 1 deletion Sparkle/SPUInformationalUpdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface SPUInformationalUpdate : NSObject <SPUResumableUpdate>

- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate;
- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate;

@end

Expand Down
4 changes: 3 additions & 1 deletion Sparkle/SPUInformationalUpdate.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ @implementation SPUInformationalUpdate
// If we ever enable auto-synthesize in the future, we'll still need this synthesize
// because the property is declared in a protocol
@synthesize updateItem = _updateItem;
@synthesize secondaryUpdateItem = _secondaryUpdateItem;
@synthesize preventsAutoupdate = _preventsAutoupdate;

- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate
- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate
{
self = [super init];
if (self != nil) {
_updateItem = updateItem;
_secondaryUpdateItem = secondaryUpdateItem;
_preventsAutoupdate = preventsAutoupdate;
}
return self;
Expand Down
Loading

0 comments on commit 84cdb0c

Please sign in to comment.