Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions FirebaseStorageUI/Sources/FIRStorageDownloadTask+SDWebImage.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@

#import "FirebaseStorageUI/Sources/Public/FirebaseStorageUI/FIRStorageDownloadTask+SDWebImage.h"

// For SPM builds the header is empty (no @import, no @interface) to keep the
// Clang module scanner happy. Provide the full import and category declaration
// here where @import is safe (compilation phase, not scan phase).
#if !__has_include(<FirebaseStorage/FirebaseStorage.h>) && !__has_include(<FirebaseStorage/FirebaseStorage-Swift.h>)
@import FirebaseStorage;
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageDownloadTask (SDWebImage) <SDWebImageOperation>
@end
NS_ASSUME_NONNULL_END
#endif

@implementation FIRStorageDownloadTask (SDWebImage)

@end
50 changes: 24 additions & 26 deletions FirebaseStorageUI/Sources/FUIStorageImageLoader.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,33 +126,31 @@ - (BOOL)canRequestImageForURL:(NSURL *)url {
}];
// Observe the progress changes
[download observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot * _Nonnull snapshot) {
// Check progressive decoding if need
// Progressive decoding requires access to partial data via the internal GTMSessionFetcher,
// which was removed in Firebase Storage 9.0.0. Guard to prevent crash; progressive rendering
// is silently skipped on Firebase 9+.
if (options & SDWebImageProgressiveLoad) {
FIRStorageDownloadTask *task = (FIRStorageDownloadTask *)snapshot.task;
// Currently, FIRStorageDownloadTask does not have the API to grab partial data
// But since FirebaseUI and Firebase are seamless component, we access the internal fetcher here
GTMSessionFetcher *fetcher = task.fetcher;
// Get the partial image data
NSData *partialData = [fetcher.downloadedData copy];
// Get response
int64_t expectedSize = fetcher.response.expectedContentLength;
expectedSize = expectedSize > 0 ? expectedSize : 0;
int64_t receivedSize = fetcher.downloadedLength;
if (expectedSize != 0) {
// Get the finish status
BOOL finished = receivedSize >= expectedSize;
// This progress block may be called on main queue or global queue (depends configuration), always dispatched on coder queue
if (coderQueue.operationCount == 0) {
[coderQueue addOperationWithBlock:^{
UIImage *image = SDImageLoaderDecodeProgressiveImageData(partialData, url, finished, task, options, context);
if (image) {
dispatch_main_async_safe(^{
if (completedBlock) {
completedBlock(image, partialData, nil, NO);
}
});
}
}];
if ([task respondsToSelector:@selector(fetcher)]) {
GTMSessionFetcher *fetcher = [task performSelector:@selector(fetcher)];
Comment on lines +134 to +135

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using performSelector: under ARC can trigger a compiler warning (-Warc-performSelector-leaks) because the compiler cannot statically verify the selector's memory management behavior.

Since fetcher is already declared in the class extension of FIRStorageTask (which FIRStorageDownloadTask inherits from) on line 45 of this file, the compiler is fully aware of the fetcher property. Therefore, you can safely access task.fetcher directly once you have guarded it with respondsToSelector:. This is cleaner, type-safe, and avoids any potential compiler warnings.

      if ([task respondsToSelector:@selector(fetcher)]) {
        GTMSessionFetcher *fetcher = task.fetcher;

NSData *partialData = [fetcher.downloadedData copy];
int64_t expectedSize = fetcher.response.expectedContentLength;
expectedSize = expectedSize > 0 ? expectedSize : 0;
int64_t receivedSize = fetcher.downloadedLength;
if (expectedSize != 0) {
BOOL finished = receivedSize >= expectedSize;
if (coderQueue.operationCount == 0) {
[coderQueue addOperationWithBlock:^{
UIImage *image = SDImageLoaderDecodeProgressiveImageData(partialData, url, finished, task, options, context);
if (image) {
dispatch_main_async_safe(^{
if (completedBlock) {
completedBlock(image, partialData, nil, NO);
}
});
}
}];
}
}
}
}
Expand All @@ -164,7 +162,7 @@ - (BOOL)canRequestImageForURL:(NSURL *)url {
}
}];

return download;
return (id<SDWebImageOperation>)download;
}

- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error {
Expand Down
8 changes: 8 additions & 0 deletions FirebaseStorageUI/Sources/NSURL+FirebaseStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
#import "FirebaseStorageUI/Sources/Public/FirebaseStorageUI/NSURL+FirebaseStorage.h"
#import <objc/runtime.h>

#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
#import <FirebaseStorage/FirebaseStorage.h>
#elif __has_include(<FirebaseStorage/FirebaseStorage-Swift.h>)
#import <FirebaseStorage/FirebaseStorage-Swift.h>
#else
@import FirebaseStorage;
#endif

@implementation NSURL (FirebaseStorage)

- (FIRStorageReference *)sd_storageReference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,24 @@
// limitations under the License.
//

#import <SDWebImage/SDWebImage.h>

// The category declaration requires FIRStorageDownloadTask to be fully defined,
// which is only possible when the CocoaPods-style headers are present.
// For SPM builds the declaration (and @import FirebaseStorage) live in the .m file
// so the Clang module scanner never sees @import here.
#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
// Firebase 8.x
// Firebase 8.x (CocoaPods)
#import <FirebaseStorage/FirebaseStorage.h>
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageDownloadTask (SDWebImage) <SDWebImageOperation>
@end
NS_ASSUME_NONNULL_END
#elif __has_include(<FirebaseStorage/FirebaseStorage-Swift.h>)
// Firebase 9.0+
// Firebase 9.0+ (CocoaPods)
#import <FirebaseStorage/FirebaseStorage-Swift.h>
#else
@import FirebaseStorage;
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageDownloadTask (SDWebImage) <SDWebImageOperation>
@end
NS_ASSUME_NONNULL_END
#endif
#import <SDWebImage/SDWebImage.h>

NS_ASSUME_NONNULL_BEGIN

// `FIRStorageDownloadTask` conforms to `SDWebImageOperation` protocol
@interface FIRStorageDownloadTask (SDWebImage) <SDWebImageOperation>

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@
// limitations under the License.
//

#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
// Firebase 8.x
#import <FirebaseStorage/FirebaseStorage.h>
#elif __has_include(<FirebaseStorage/FirebaseStorage-Swift.h>)
// Firebase 9.0+
#import <FirebaseStorage/FirebaseStorage-Swift.h>
#else
@import FirebaseStorage;
#endif
#import <SDWebImage/SDWebImage.h>

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
#import <Foundation/Foundation.h>

#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
// Firebase 8.x
// Firebase 8.x (CocoaPods)
#import <FirebaseStorage/FirebaseStorage.h>
#elif __has_include(<FirebaseStorage/FirebaseStorage-Swift.h>)
// Firebase 9.0+
// Firebase 9.0+ (CocoaPods)
#import <FirebaseStorage/FirebaseStorage-Swift.h>
#else
@import FirebaseStorage;
// Swift Package Manager: forward declaration only.
@class FIRStorageReference;
#endif

NS_ASSUME_NONNULL_BEGIN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,18 @@
#import <UIKit/UIKit.h>

#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
// Firebase 8.x
// Firebase 8.x (CocoaPods)
#import <FirebaseStorage/FirebaseStorage.h>
#elif (__has_include(<FirebaseStorage/FirebaseStorage-Swift.h>))
// Firebase 9.0+
// Firebase 9.0+ (CocoaPods)
#import <FirebaseStorage/FirebaseStorage-Swift.h>
#else
// If you're using FirebaseStorageUI via Swift Package Manager
// from a Swift or mixed Swift/ObjC build target, you will need
// to add
// -Xcc -fmodule-map-file=$(GENERATED_MODULEMAP_DIR)/FirebaseStorage.modulemap
// to your target's Other Swift Flags build setting.
// See
// https://github.com/firebase/FirebaseUI-iOS/issues/1028#issuecomment-1262689219
// for more details.
@import FirebaseStorage;
// Swift Package Manager: forward declarations only to avoid Clang module-scanner
// failures. Your app target must `@import FirebaseStorage` (or `import FirebaseStorage`
// in Swift) separately.
@class FIRStorage;
@class FIRStorageReference;
@class FIRStorageDownloadTask;
#endif
#import <SDWebImage/SDWebImage.h>

Expand Down
8 changes: 8 additions & 0 deletions FirebaseStorageUI/Sources/UIImageView+FirebaseStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
#import "FirebaseStorageUI/Sources/Public/FirebaseStorageUI/UIImageView+FirebaseStorage.h"
#import "FirebaseStorageUI/Sources/Public/FirebaseStorageUI/FUIStorageImageLoader.h"

#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
#import <FirebaseStorage/FirebaseStorage.h>
#elif __has_include(<FirebaseStorage/FirebaseStorage-Swift.h>)
#import <FirebaseStorage/FirebaseStorage-Swift.h>
#else
@import FirebaseStorage;
#endif

@implementation UIImageView (FirebaseStorage)

- (void)sd_setImageWithStorageReference:(FIRStorageReference *)storageRef {
Expand Down
Loading