Now I'm involved in a project which needs to download a huge amount of images from server. Following the recommendation online, I tried the ASIHttpRequest. But when I copied all the necessary classes into my project, I got 30+ errors in those classes. Most of the errors are about using retain, release or autorelease. Because I'm using Xcode 4.2.1, explicit retain, release and autorelease is forbidden. But some other errors are quite ridiculous.
for example, in class ASIDataCompressor.m, following method should return NSData
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish
but I see one portion of the method return NO
if (status == Z_STREAM_END) {
break;
} else if (status != Z_OK) {
if (err) {
*err = [[self class] deflateErrorWithCode:status];
}
return NO;
}
Some other classes also have similar problems.
My questions are:
Did I download the wrong package?
How to let compiler ignore those explicit retain, release and autorelease?
"Xcode 4.2.1, explicit retain, release and autorelease is forbidden" because you have ARC enabled when you created your project. Disable ARC.
ASIDataCompressor.m method looks fine here. Don't know how you got it wrong.
Since you just picked up ASIHTTP in your project I would recommend switching to AFNetworking because read this: [request release]
As stated above, when using ARC, you cannot use (and no longer need) retain/release/etc.
If you want your overall project to still have ARC, you can disable it for that one file.
When you migrate a project to use ARC, the -fobjc-arc compiler flag is set as the default for all Objective-C source files. You can disable ARC for a specific class using the -fno-objc-arc compiler flag for that class.
In Xcode, go to target Build Phases tab > open the Compile Sources group to reveal the source file list > double-click the file for which you want to set the flag > enter -fno-objc-arc in the pop-up panel, then click Done.
Related
I am seeing the compiler warn that "Instance method -cacheKeyForURL not found" and "Instance method -defaultCachePathForKey not found", in the following code:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
NSString *cacheKey = [manager cacheKeyForURL:[NSURL URLWithString:imageUrl]];
NSString *cachePath = [[manager imageCache] defaultCachePathForKey:cacheKey];
Yet clearly, these methods are defined. Here, for example, is the method definition in SDImageCache.h:
/**
* Get the default cache path for a certain key
*
* #param key the key (can be obtained from url using cacheKeyForURL)
*
* #return the default cache path
*/
- (NSString *)defaultCachePathForKey:(NSString *)key;
At the top of my code file, I am including the relevant files from the SDWebImage project:
#import <SDWebImage/UIImageView+WebCache.h>
#import <SDWebImage/SDImageCache.h>
#import <SDWebImage/SDWebImageManager.h>
Moreover, sharedImageManager is defined in SDWebImageManager.h and the compiler is having no problems finding it. I only have warnings on the 2nd and 3rd lines.
My code runs fine and these methods both work without crashing. Why is the compiler telling me it cannot find it?
I am running XCode 6, compiling for Active Architecture Only, iPhone 6 Simulator.
UPDATE
When I compile for Distribution, "All Architectures", suddenly it can find cacheKeyForURL and defaultCachePathForKey, no problem, but setImageWithURL is now deprecated?
I do see the deprecation warnings in UIImageView+WebCache.h, but I'm just super-confused why building for these different architectures is turning on/off various compiler warnings when the header files of SDWebImage don't seem to have anything architecture-specific to them.
I figured this out by more closely inspecting the error in the "Report Navigator" (neé Log Navigator).
It turns out that there were some very old SDWebImageManager.h files in the "Derived Data" folder that it was choosing to link against. Unclear why they did not go away upon a clean of my project. (Possibly connected to the fact that I migrated from submodules to including SDWebImage via Cocoapods?)
I used this answer on Stack Overflow to navigate to my DerivedData folder, and then I manually deleted the subfolder for my project. After doing that, the project now builds successfully without the spurious warnings.
In Objective-C, do all source files in the project get compiled and linked into the final binary even if they are not imported by any classes?
That depends on your target settings. If you go to the target's Build Phases, anything listed under Compile Sources will be compiled.
If the source file is part of the build then its classes end up in the binary and available at runtime. That's because the runtime is reflective and can be queried later to find them. The compiler cannot be certain that won't happen.
EDIT: a classic use case is an informal protocol. You may write code like:
- (void)initWithObject:(id)object
{
self = [super init];
if(self)
{
_title = [object title];
_value = [object value];
}
return self;
}
Then you might decide you want to add an implementation of that informal protocol to e.g. NSString:
#interface NSString (MYPropertyProtocol)
#end
#implementation NSString (MYPropertyProtocol)
- (NSString *)title
{
return #"Content";
}
- (NSString *)value
{
return self;
}
#end
Just because nobody imports the NSString category doesn't mean the methods aren't used.
Going beyond that, in my current app we have a protocol like (this is a heavily cut-down version):
#protocol MYTableViewCell
+ (NSArray *)acceptedObjectClasses;
- (void)setObject:(id)object;
#end
Subsequently UITableView subclasses can opt to implement MYTableViewCell. If so they are found automatically by traversing objc_getClassList (and a lot of caching) and used automatically by my table view data source if it wants to display any object type declared as supported by acceptedObjectClasses. So that's taken most of the hassle out of writing the table view data source — I've got just one, which can accept any combination of objects used anywhere in the app, yet it's very short and easy mentally to check for errors, and need never grow even as the app learns about more things that need to be displayed in tables.
Nobody ever explicitly imports those table view cells, because it'd just mean having to do the same work twice — declare the class in Objective-C, which the compiler will check for me, then go and redeclare it to the custom cut-down lookup system that I've implemented instead of just using Objective-C's, which I probably need to do manual verification on.
Click on a .m file in the Project Navigator on the left side of Xcode, then open the right-hand tile (with the right-hand "View" button in the toolbar) and look at the "Target Membership" section. There is a checkbox with your project name beside it. If the box is checked, that .m file is included in the build. If the checkbox is not checked then the .m is essentially ignored.
You can also check this by clicking on your project name at the top of the ProjectNavigator column, selecting the project under "TARGETS", selecting "Build Phases", and selecting "Compile Sources". All of the included .m files will be shown and you can add or delete files from the list using the + - buttons at the bottom of the list.
I really have no idea why on this particular project my debugger is extremely 'disabled'.
For example I'll want to get info on an object:
(lldb) po [_model dictionaryValue]
[no Objective-C description available]
I'm wondering why this is. It's making debugging extremely difficult and it's only on this current project. I'm guessing I've done something to the settings at some point. It's on almost any po someObject I try to inspect. The variables in scope can be seen in the pane to the left of the debug console however.
I'm on Xcode 5, I have Cocoapods in my project, and it's a Unit Testing Target.
Any insights or any way to fix this?
Update:
For clarity, part of how the test case is implemented:
#interface WWCGateModelTests : XCTestCase
{
WWCGate *_model;
}
#end
#implementation WWCGateModelTests
- (void)setUp
{
[super setUp];
// Put setup code here; it will be run once, before each test case.
_model = [WWCGate loadGateModelWithIdentifier: kGateName]; // defined, not nil
}
- (void)tearDown
{
[super tearDown];
NSError *error = nil;
[_model saveModelOrError:&error];
// Breakpoint here. po _model does not print the model.
// This has been possible with other projects... po error will print
// nil to the console. How is an ivar not in scope?
}
This is likely happening because Unit Testing Targets typically are set up to run with "Release" configurations. "Release" configurations are ones where the debugging symbols have been stripped or optimized away.
I suspect you won't have this problem if you make certain you're running with a non-optimized, symbols-in-place Debug version of your app. You can change that in Xcode's scheme editor (e.g. when doing "Test" or "Profile", use the "Debug" configuration).
Are you sure you aren't using it on primitive types? Use p intVariable on those.
Every object will respond to description by at least printing class and memory address.
I've tracked down the issue (but haven't fixed it fully yet). It has to do with the Mantle Framework. In its description method it wants to spit out the contents of an NSDictionary that it generates at that point. There's something wrong with the way I set up my model I believe so creating this dictionary (based probably on how I configured some property) is basically failing.
I overrode the description method to return a standard description:
- (NSString*)description
{
return [NSString stringWithFormat:#"<%#: %p>", self.class, self];
}
and everything is fine and good again on planet Earth. ;-)
Thanks to those who were particularly patient. A more detailed discussion about this issue can be found at UPDATE 3 of the following post: http://horseshoe7.wordpress.com/2013/05/26/hands-on-with-the-mantle-model-framework/
Already checked this question: Weak linking UIPopoverBackgroundView
and already read: http://www.marco.org/2010/11/22/supporting-older-versions-of-ios-while-using-new-apis#fnref:1
I have a custom PopoverBackgroundView declared in a .h and implemented in a .m file. Then, in just one file, I instantiate it like this
self.settingsPopover.popoverBackgroundViewClass = [CustomPopoverBackgroundView class];
I´ve tried doing it like marco says in the link above:
if ([UIPopoverBackgroundView class] != nil) {
self.settingsPopover.popoverBackgroundViewClass = [CustomPopoverBackgroundView class];
}
But I get the same launch error when I run in a 4.3 ipad simulator
dyld: Symbol not found: _OBJC_CLASS_$_UIPopoverBackgroundView
My base sdk is IOS 5.1, and my target deployment is 5.1 as well. Im using LLVM compiler 4.0.
Any ideas? Thanks a lot!
Have you tried using respondsToSelector with the relevant UIPopoverController setBackgroundViewClass method? Remember that properties automatically generate setter and getter methods that you can use in addition to the normal property syntax.
The reason why you're still getting linker errors is because you're still trying to call a method on that class, which doesn't exist.
If it's a case that the entire class doesn't exist, Apple recommends using NSClassFromString(#"UIPopoverController") and checking if the returned result is nil.
When I create a new project with Xcode 4.4 and add these lines:
NSDictionary *test = #{ #"key" : #"test value" };
NSString *value = test[#"key"];
NSLog(#"value is: %#", value);
it compiles with no warnings and executes as expected.
Adding the same lines to an existing project produces the compiler error:
NSString *value = test[#"key"]; <-- Expected method to read dictionary element not found on object of type 'NSDictionary *'
I compared both projects' target build settings but nothing leapt out at me.
Update:
The new project that successfully compiled was for OSX. I tried another new one for iOS with the above lines and it fails to compile, same as my pre-existing (iOS) project.
This has nothing to do with old vs. new project, but rather is a factor of the SDK you use. The problem you're running into is that while this is a compiler feature, it requires SDK support. The iOS 5 SDK does not provide that support, though the iOS 6 SDK does.
For that reason, now you should just use the iOS 6 SDK. Read on if you want to use object subscripting with the iOS 5 SDK.
All you need to do is add a header file so that the compiler will try the call. There's no need to add an implementation; it's handled automatically by arclite. (If you are not using ARC, you will have to force the linker to include arclite. But you still don't have to actually switch to it.)
Create a new interface file, NSObject+subscripts.h.
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000
#interface NSDictionary(subscripts)
- (id)objectForKeyedSubscript:(id)key;
#end
#interface NSMutableDictionary(subscripts)
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
#end
#interface NSArray(subscripts)
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
#end
#interface NSMutableArray(subscripts)
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
#end
#endif
I've put this chunk on github.
Note: I used to suggest adding the required methods to NSObject before explaining how to add them only to the relevant objects. In retrospect, I believe this was an error on my part; it led to errors being caught at runtime rather than compile time, unlike the approach now presented here. That approach is still on my blog, but I now believe it to be more of a cool hack than a useful approach.
Source:
Peter Steinberger, Using Subscripting With Xcode 4.4 and iOS 4.3+