[__NSDate objCType]: unrecognized selector - iphone

Sometimes I got error saying that unrecognized selector objcType was sent to an NSDate object:
2011-06-11 14:44:51.589 MyApp[354:307] -[__NSDate objCType]:
unrecognized selector sent to instance 0x4b0d5a0
2011-06-11 14:44:51.732 MyApp[354:307] * Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDate
objCType]: unrecognized selector sent to instance 0x4b0d5a0'
What I do is loading data from sqLite using Core Data by calling [[self fetchedResultsController] performFetch:&error]. I use a predicate, which ensures that the only (NSManaged)objects having their attribute kickoffTime of type NSDate in a specified range are fetched:
NSDate * fromDate = ...
NSDate * toDate = ...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"( ( %# <= kickoffTime +0 ) && ( kickoffTime +0 <= %# ) )", fromDate, toDate];
// Add the predicate to the fetchRequest
[[[self fetchedResultsController] fetchRequest] setPredicate:predicate];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
...
}
I do not really know what the problem might be. I probably misuse the core data predicate in some way, forcing the framework to send the objCType message to NSDate object in order to find out type of the object. Does anybody have some suggestions?
Here is a few things I have observed:
the NSDate object to which is sent the problematic selector is the kickoffTime attribute of my NSManagedObject
it happens pretty randomly so it is not easy to reproduce
the NSDate object to which the unrecognized selector is sent appears to be valid object (I could print it out in gdb)
Here is the top of the stack:
0 CoreFoundation 0x3587a987
__exceptionPreprocess + 114
1 libobjc.A.dylib 0x34a8249d
objc_exception_throw + 24
2 CoreFoundation 0x3587c133
-[NSObject(NSObject) doesNotRecognizeSelector:] + 102
3 CoreFoundation 0x35823aa9 forwarding +
508
4 CoreFoundation 0x35823860
_CF_forwarding_prep_0 + 48
5 Foundation 0x3121ac69
+[_NSPredicateUtilities add:to:] + 40
6 Foundation 0x31221225
-[NSFunctionExpression expressionValueWithObject:context:] + 688
7 Foundation 0x3117e045
-[NSComparisonPredicate evaluateWithObject:substitutionVariables:] +
176
8 Foundation 0x312255fb
-[NSCompoundPredicateOperator
evaluatePredicates:withObject:substitutionVariables:] + 186
9 Foundation 0x3121e43f
-[NSCompoundPredicate evaluateWithObject:substitutionVariables:] + 186
10 Foundation 0x3117df8d -[NSPredicate
evaluateWithObject:] + 16
11 CoreData 0x356e8edf
-[NSManagedObjectContext executeFetchRequest:error:] + 2014
12 CoreData 0x357a041b
-[NSFetchedResultsController performFetch:] + 766
13 MyApp 0x000195ef
-[MatchesCalendarDataSource loadMatchesFrom:to:delegate:] + 138

The objcType is a selector/method of NSValue and its subclasses like NSNumber. That means that the NSDate object is being treated like a NSValue at some point. It most likely happens when the NSDate is being wedged into a mathematical operation which it doesn't support.
In a predicate, a NSDate will often be converted to a NSTimeInterval which is a double. If you log the predicate you have above, the date will resolve something like this:
CAST(335110182.022141, "NSDate") <= kickoffTime + 0 AND kickoffTime + 0 <= CAST(335110182.022141, "NSDate")
... which is the NSDate being cast to a double. That is where your problem comes from. I suspect it arises because the predicate parser cannot always resolve the precedence.
You can probably resolve the problem just by:
(CAST(335110182.022141, "NSDate") <= kickoffTime + 0) AND (kickoffTime + 0 <= CAST(335110182.022141, "NSDate"))
However, the +0 does absolutely nothing in a predicate besides cause problems so I would just lose it.
BTW when you say:
What I do is loading data from sqLite using Core Data by calling
... that suggest that you are thinking of Core Data as an object wrapper for sqlite. It isn't and thinking that way will get you into trouble especially with predicates.

Related

Swift String rare crash

In my app I have a logger that writes errors and status messages to a string. It's not written to a file, it's just handy to have something to look at when a bug happens without an attached debug session.
The addLog() method is called approx. 0-10 times every 3 seconds and is fairly simple:
every call adds the new addition to the beginning of the string along with the second it has happened
to prevent the string from blowing up in terms of size, if it exceeds 2kb, it will successively cut the "oldest" 100 log characters until it's smaller than 2kb again
The code looks as following:
var logString = ""
func addLog(s : String){
let date = Date()
logString = "\(date.second)\(s).\n\(logString)"
while(logString.count>2000){
logString=String(logString.dropLast(100))
}
}
I've never seen anything wrong with it until today when I received a crash log:
Thread 5 name:
Thread 5 Crashed:
0 libsystem_kernel.dylib 0x00000001c00f5414 __pthread_kill + 8
1 libsystem_pthread.dylib 0x00000001ddc50b50 pthread_kill + 272 (pthread.c:1392)
2 libsystem_c.dylib 0x000000019b5d3b74 abort + 104 (abort.c:110)
3 libsystem_malloc.dylib 0x00000001a1faf49c malloc_vreport + 560 (malloc_printf.c:183)
4 libsystem_malloc.dylib 0x00000001a1faf740 malloc_zone_error + 104 (malloc_printf.c:219)
5 libsystem_malloc.dylib 0x00000001a1f99ed8 free_small_botch + 40 (magazine_small.c:2215)
6 libswiftCore.dylib 0x00000001961103d8 _swift_release_dealloc + 40 (HeapObject.cpp:648)
7 APPNAME 0x00000001046b56a0 AppDelegate.addLog(s:) + 960 (AppDelegate.swift:0)
What's weird about the log itself is that the addLog() function is not in line 0 of my AppDelegate but maybe that's normal to have the wrong line in the crash report.
The only possible explanation for this issue that I can come up with is that there is an issue with thread safety in my function, or that I have missed something regarding the garbage collection in swift. It's very likely that the function is called from different threads at the same time, could that be an issue? Or do I have to get into the objective-c times retain etc. again to resolve this? What can I make out of this crash log?
You must handle all changes in serial queue. The simple modification:
private let queue = DispatchQueue(label: "addlog.queue")
private var logString = ""
func addLog(s : String) {
queue.async { [weak self] in
guard let self = self else { return }
let date = Date()
self.logString = String("\(date.second)\(s).\n\(self.logString)".prefix(2000))
}
}
In your case you can read and write the "logString" parameter from different threads, using serial DispatchQueue for handle all actions with parameter make unavailable to read and write parameter at one moment of time

does swift not allow initialization in function parameters?

This first block generates a generic Swift Compile Error (doesn't even point to the line)
let screenDivision = size.width / 5;
var game1 = SKSpriteNode(color: .redColor(), size: CGSize(width: 2 * screenDivision, height: size.height));
This second block works fine.
let screenDivision = size.width / 5;
var a = CGSize(width: 2 * screenDivision, height: size.height)
var game1 = SKSpriteNode(color: .redColor(), size: a);
Why? I'd hate to run into this error again and not remember where I wrote such code.
(I also need to pass it a variable, not a constant? Wtf... [if I change var a, to let a, I get the compile error])
The error goes away if you include UIColor in your call to redColor:
let screenDivision = size.width / 5;
var game1 = SKSpriteNode(
color: UIColor.redColor(),
size: CGSize(width: 2 * screenDivision,
height: size.height)
)
I am not aware of the ability to leave out type names for class methods. I am only aware of that being possible with Enumeration cases. The Swift programming guide mentions specifically that this is possible with enumerations but says nothing in the type method section.
I am actually surprised that the second version works. For now, I would always include the type name unless you are referring to an enumeration case.
It seems, it's a compiler bug.
In this case, "Implicit Member Expression" should be performed.
An implicit member expression is an abbreviated way to access a member of a type, such as an enumeration case or a class method, in a context where type inference can determine the implied type. It has the following form:
.member name
I reproduced exact the same problem with this code:
class MyClass {
class func create() -> MyClass { return MyClass() }
}
func f(arg:MyClass!, arg2:Int) { }
f(.create(), 1)
/*
Bitcast requires both operands to be pointer or neither
%.asUnsubstituted = bitcast %C4test7MyClass* %6 to i64
LLVM ERROR: Broken function found, compilation aborted!
*/
or even with enum:
enum MyEnum {
case Case1
}
func f(arg:MyEnum!, arg2:Int) { }
f(.Case1, 1)
/*
0 swift 0x00000001062d8a68 llvm::sys::PrintStackTrace(__sFILE*) + 40
1 swift 0x00000001062d8f54 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff8a314f1a _sigtramp + 26
3 libsystem_platform.dylib 0x00007fd8085362e8 _sigtramp + 2116162536
4 swift 0x00000001056e8e98 emitApplyArgument((anonymous namespace)::IRGenSILFunction&, swift::SILValue, swift::SILParameterInfo, llvm::ArrayRef<swift::Substitution>, swift::irgen::Explosion&) + 456
5 swift 0x00000001056e5f1d swift::SILVisitor<(anonymous namespace)::IRGenSILFunction, void>::visit(swift::ValueBase*) + 34605
6 swift 0x00000001056dcbab swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 9179
7 swift 0x0000000105656347 swift::irgen::IRGenModule::emitLazyDefinitions() + 199
8 swift 0x00000001056c9966 performIRGeneration(swift::IRGenOptions&, swift::Module*, swift::SILModule*, llvm::StringRef, llvm::LLVMContext&, swift::SourceFile*, unsigned int) + 2038
9 swift 0x00000001056ca2e3 swift::performIRGeneration(swift::IRGenOptions&, swift::SourceFile&, swift::SILModule*, llvm::StringRef, llvm::LLVMContext&, unsigned int) + 51
10 swift 0x000000010561f5f4 frontend_main(llvm::ArrayRef<char const*>, char const*, void*) + 5444
11 swift 0x000000010561c96d main + 1677
12 libdyld.dylib 0x00007fff90b525c9 start + 1
13 libdyld.dylib 0x0000000000000010 start + 1867176520
Stack dump:
0. Program arguments: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file test.swift -target x86_64-apple-darwin14.0.0 -target-cpu core2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -color-diagnostics -module-name test -o /var/folders/kb/xgglxb597sv6h8b744d5vft00000gn/T/test-4cf5cc.o
1. While emitting IR SIL function #top_level_code<unknown>:0: error: unable to execute command: Segmentation fault: 11
<unknown>:0: error: swift frontend command failed due to signal (use -v to see invocation)
*/
Both cases, removing ! from the function parameter solves the problem.
Let's say: "DO NOT USE implicit member expression for implicitly unwrapped optional context"

Why sometimes 'self' isn't available while debugging with lldb?

A lot of time (when it's not every time) I got the following error when I try to print objects on lldb. Is there some build/debug configuration to change or is this an error inside lldb?
(lldb) po userLevel
error: warning: Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context
error: use of undeclared identifier 'userLevel'
error: 1 errors parsing expression
I build with llvm and do not strip debug symbols.
Edit: Here is the backtrace:
(lldb) bt
* thread #1: tid = 0x1c03, 0x001169c5 FanCake-Beta`-[KWUserLevelController addPoints:](, _cmd=0x0029187b, points=15) + 179 at KWUserLevelController.m:53, stop reason = step over
frame #0: 0x001169c5 FanCake-Beta`-[KWUserLevelController addPoints:](, _cmd=0x0029187b, points=15) + 179 at KWUserLevelController.m:53
frame #1: 0x00112172 FanCake-Beta`-[KWEventRealTimeControllergameEngine:hostedGame:didSucceedIn:withScore:](self=0x0b9d7740, _cmd=0x0027a2a7, engine=0x1be5af40, game=0x1be5a850, completionTime=3.59473554800206, score=0) + 421 at KWEventRealTimeController.m:647
frame #2: 0x0007189a FanCake-Beta`__35-[KMCatchEmGameEngine animateStep6]_block_invoke197(, finished='\x01') + 257 at KMCatchEmGameEngine.m:214
frame #3: 0x01990df6 UIKit`-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 223
frame #4: 0x01983d66 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 237
frame #5: 0x01983f04 UIKit`-[UIViewAnimationState animationDidStop:finished:] + 68
frame #6: 0x017587d8 QuartzCore`CA::Layer::run_animation_callbacks(void*) + 284
frame #7: 0x03634014 libdispatch.dylib`_dispatch_client_callout + 14
frame #8: 0x036247d5 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 296
frame #9: 0x04737af5 CoreFoundation`__CFRunLoopRun + 1925
frame #10: 0x04736f44 CoreFoundation`CFRunLoopRunSpecific + 276
frame #11: 0x04736e1b CoreFoundation`CFRunLoopRunInMode + 123
frame #12: 0x040367e3 GraphicsServices`GSEventRunModal + 88
frame #13: 0x04036668 GraphicsServices`GSEventRun + 104
frame #14: 0x01945ffc UIKit`UIApplicationMain + 1211
frame #15: 0x000039a8 FanCake-Beta`main(argc=1, argv=0xbffff354) + 94 at main.m:13
frame #16: 0x00002dc5 FanCake-Beta`start + 53
Edit 2: Same thing when I try to print local vars
(lldb) po currentUser
error: variable not available
If I put some NSLog() in the code, the correct value is printing. But not with the po command.
I usually get this error when I have compiler optimization turned on. The compiler will generate code which does not necessarily follow your code logic flow.
Go to your project in the navigator -> Target -> Build settings -> Search for optimization level -> expand optimization level -> select the debug line -> change to none in both columns of your project and target.
Hope this helps.
I was having this problem and it went away when I edited my scheme and set the Run build to Debug. I had set it to AdHoc for testing Push Notifications and that apparently makes LLDB unhappy.
Because it's optimized away. Let's use an example:
void f(int self) {
// Here, "self" is live:Its value is used in the call to NSLog()
NSLog(#"I am %d",self);
// Here, "self" is dead: Its value is never used.
// I could do self=0 or self=self*self and nobody would know.
// An optimizing compiler will typically optimize it away.
// It might still be on the stack (in the parameters passed to NSLog())
// but the compiler shouldn't assume this.
NSLog(#"Another function call: %d", 1);
// If "self" was on the stack, it will probably now have been overwritten.
}
Compilers do a lot of things to make your code faster/smaller; forgetting about variables which are no longer needed is a very common optimization.
As already said in this other question:
In Build Settings, setting Precompile Prefix Header to NO fixed it for me.

Capture Video and Audio and write it to server in iPhone

I tried to capture video and write it to following url.I am getting this error.
Code:
videoURL = [[NSURL alloc] initWithString:#"http://belterra.webiguide.com/uploadimages/VideoRecord.mpeg4"];
_videoWriter = [[AVAssetWriter alloc] initWithURL:videoURL fileType:AVFileTypeQuickTimeMovie
error:&error];
Exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -[AVAssetWriter initWithURL:fileType:error:]
invalid parameter not satisfying: [outputURL isFileURL]'
*** Call stack at first throw:
(
0 CoreFoundation 0x314d0987 __exceptionPreprocess + 114
1 libobjc.A.dylib 0x319a149d objc_exception_throw + 24
2 AVFoundation 0x30690421 -[AVAssetWriter initWithURL:fileType:error:] + 188
3 iChat 0x00003155 -[AVCaptureVideo setupWriter] + 116
4 iChat 0x000030a3 -[AVCaptureVideo startVideoRecording] + 26
5 iChat 0x000039ed -[AVCaptureVideo initCapture] + 1112
<snip>
)
invalid parameter not satisfying: [outputURL isFileURL]'
It looks like it's expecting a local file path but in URL format e.g. file://....
from the docs
Initializes an asset writer for writing to the file identified by a given URL in a format specified by a given UTI.
You would then have to manage the upload to your webserver separately.

Why does my iPhone app update from App Store fail while upgrading the database?

I've released an app update which does an upgrade of the database ie. executes a script file in the bundle that adds a column to existing table , etc. I've tested this by deploying previous version builds on my device from xcode and then deploying the latest version. The upgrade worked fine.
Yesterday my distribution build got accepted to app store. When I start it up , my nightmare scenario materialized , it fails during DB upgrade! I've checked the distribution build and the upgradeSQL file is there , so it doesn't seem to be a missing resource file all though I'm not sure. I have no idea how I should debug this. What is the difference between a distribution build from app store and a release/debug build deployed from xcode , apart from code signing? Doesn't make sense to me.
This is my crash log and the code that fails:
0 libSystem.B.dylib 0x3141d414 pread + 20
1 libsqlite3.0.dylib 0x303a2154 unixRead + 40
2 libsqlite3.0.dylib 0x303bd7c4 sqlite3PagerAcquire + 3748
3 libsqlite3.0.dylib 0x303c7718 sqlite3BtreeNext + 260
4 libsqlite3.0.dylib 0x303c7b84 sqlite3BtreeNext + 1392
5 libsqlite3.0.dylib 0x304272b8 sqlite3VdbeExec + 38668
6 libsqlite3.0.dylib 0x30428944 sqlite3Step + 504
7 libsqlite3.0.dylib 0x303ecbc4 sqlite3_exec + 600
8 MyApp 0x00046ae4 +[DBUpgradeService executeUpgradeScript:] (DBUpgradeService.m:94)
9 MyApp 0x000469aa +[DBUpgradeService upgradeV1_0ToV1_1] (DBUpgradeService.m:67)
10 MyApp 0x0004687a +[DBUpgradeService upgradeDBIfNecessary] (DBUpgradeService.m:27)
11 MyApp 0x000021ec -[MyAppAppDelegate applicationDidFinishLaunching:] (MyAppAppDelegate.m:49)
12 UIKit 0x30a4ef24 -[UIApplication performInitializationWithURL:asPanel:] + 160
13 UIKit 0x30a57dec -[UIApplication _runWithURL:] + 644
14 Foundation 0x306945a2 __NSFireDelayedPerform + 326
15 CoreFoundation 0x30269d88 CFRunLoopRunSpecific + 2642
16 CoreFoundation 0x30269320 CFRunLoopRunInMode + 44
17 GraphicsServices 0x31567e58 GSEventRunModal + 268
18 UIKit 0x30a4fa6c -[UIApplication _run] + 520
19 UIKit 0x30a591d0 UIApplicationMain + 1132
20 MyApp 0x00002090 main (main.m:20)
21 MyApp 0x0000202c start + 44
+ (BOOL) executeUpgradeScript:(NSString*) scriptName{
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *scriptPath = [resourcePath stringByAppendingPathComponent:scriptName];
NSString* upgradeScript = [NSString stringWithContentsOfFile:scriptPath];
NSArray* lines = [upgradeScript componentsSeparatedByString:#"\n"];
//begin transaction
NSString* begin = [NSString stringWithString:#"BEGIN TRANSACTION"];
sqlite3_exec([DatabaseManager getDatabase], begin.UTF8String , nil , nil , nil);
BOOL failed = NO;
for( NSString* line in lines) {
const char *sql = line.UTF8String;
char* error = nil;
sqlite3_exec([DatabaseManager getDatabase], sql , nil , nil , &error); //THIS LINE FAILS
if(error != nil) {
NSLog([NSString stringWithCString:error]);
failed = YES;
break;
}
}
if(failed){
return NO;
}
else{
NSString* commit = [NSString stringWithString:#"COMMIT"];
sqlite3_exec([DatabaseManager getDatabase], commit.UTF8String , nil , nil , nil);
return YES;
}
}
If the upgrade of the DB takes to long time in the launch phase an app can be kicked out.
One way to resolve such a problem could be to put the upgrade in a NSThread
- (void)upgradeSomething:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Do something here that takes time
// and maybe signal when done with some flag or thing...
[pool release];
}
- (void)awakeFromNib
{
// The usual stuff
// and detach a NSThread for upgrade
[NSThread detachNewThreadSelector:#selector(upgradeSomething:)
toTarget:self
withObject:nil]
}
Read here for reason for keeping the event loop active.
You aren't allowed to modify files in your application bundle (see epatel's link). As part of your build process, the app gets signed, and modifying files in the bundle will break the signature.
You should be using your application's document directory. You should replace your resourcePath assignment with:
NSString *resourcePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];